# Verwirrung: Per SSH werden manche Befehle ausgeführt, manche nicht



## Knödel0815 (5. Apr 2012)

Hallo.

Ich bin nicht ganz sicher, ob ich im richtigen Unterpunkt poste, aber es gab keinen SSH-Unterpunkt, also dachte ich, bei XML wird man damit wohl meist zu tun haben. Ich hoffe, das war richtig.

Ich bin gerade ziemlch verwirrt. In meinem Java-Code verbinde ich mich mit einem Server (Linux ist daraf Betriebssystem.) und möchte die SSH-Version abfragen (also ssh -V). 
Führe ich den Befehl im PuTTY aus, gibt er mir auch ganz normal die SSH-Version aus. Da funktioniert der Befehl also.
Doch im Java-Code bekomme ich immer _null_. (Also null schreibt er ins XML-File und in der Konsole gibt er mir nichts aus.)

Schreibe ich nun aber an die Stelle, wo ich den Befehl ssh -V gebe, stattdessen zum Beispiel uname -a hin, gibt er mir in der Konsole exakt das aus (und schreibt es ins XML-File), was er auch in PuTTY darauf ausgibt.

Gibt es da vielleicht Besonderheiten, die einige Befehle betreffen? Oder hat sonst schonmal jemand ähnliche Erfahrungen gemacht und hätte eine Lösungsidee für mich?

Vielen Dank im Voraus.


Ich poste mal das betreffende Codestück mit. 

P.S.: Ich arbeite noch nicht allzu lange mit Java, also bitte seht darüber hinweg, wenn der Code eventuell unschön ist.


```
public class XMLSSHTest {
	public static void main(String[] args) {
	    // Hier stehen die Daten des Webservers.
	    String hostname = "XXX.XXX.XXX.XXX";
	    String username = "XXXXXXXX";
	    String password = "XXXXXXXXXXXX";
	    
	    try {
	      // Hier erfolgt die Instanziierung der Verbindung.

	      Connection conn = new Connection(hostname);

	      // Dies ist die Verbindung. Danach wird eine Erfolgsmeldung
	      // ausgegeben.

	      conn.connect();
	      System.out.println("Connection successful.");

	      // Nun erfolgt die Authentifizierung. Dies ist die Variante mit
	      // Passwort. (Es wäre auch noch eine Authentifizierung mit PublicKey
	      // möglich, aber das ist in diesem Fall zu umständlich.)
	      // Es erfolgt eine Ausgabe über Erfolg oder Misserfolg der
	      // Authentifizierung.

	      boolean isAuthenticated = conn.authenticateWithPassword(username,
	          password);

	      if (isAuthenticated == false)
	        throw new IOException("Authentication failed.");
	      else
	        System.out.println("Authentification successful.");

	      // Hier wird eine Session erstellt, in der dann die Befehle
	      // ausgeführt werden können.

	      Session sion = conn.openSession();
	      System.out.println("Session started.");

	      // Als Beispiel erfolgt hier der Befehle "ssh -V".
                   [B]// Wenn ich genau hier uname -a hinschreibe, macht das Programm alles, wie es soll.[/B]

	      sion.execCommand("ssh -V"); 
	      
	      System.out.println("Hier sind ein paar Informationen zum Host:");

	      /* Show exit status, if available (otherwise "null") */
                   // Ich weiß ehrlich gesagt nicht, was die Passage tut. Irgendein Fehlerabfang?

	     System.out.println("ExitCode: " + sion.getExitStatus());

	      // Hier erfolgt die Erstellung des OutputStreams.

	      try {
	        OutputStream fout = new FileOutputStream("SSHTest.xml", true);
	        OutputStream bout = new BufferedOutputStream(fout);
	        OutputStreamWriter out = new OutputStreamWriter(bout, "8859_1");

	        // Hier erfolgt die Erstellung des InputStreams.

	        InputStream ddout = new StreamGobbler(sion.getStdout());
	   
	        // Dies ist die Abfrage der Informationen vom Server.
	        
	            BufferedReader br4 = new BufferedReader(new InputStreamReader(
	                              ddout));
	                          while (true) {
	                            String line4 = br4.readLine();

	          //Die Infrmationen des Servers werden ins XML-File geschrieben.

	         // out.write("<?xml version=\"1.0\" ");
	         // out.write("encoding=\"ISO-8859-1\"?>\r\n");
	          out.write("ssh -V: ");
	          out.write(line4 + "\r\n");
	          
	          out.flush(); // Don't forget to flush!
	          out.close();

	          // Die Aufbereitung der Daten zur Ausgabe in der Console.
	              if (line4 == null)
	                  break;
	                System.out.println(line4);
	       
	      }}

	      //Die Fehlerverarbeitung für das Schreiben ins XML-File.

	      catch (UnsupportedEncodingException e) {
	        System.out
	            .println("This VM does not support the Latin-1 character set.");
	      } catch (IOException e) {
	        System.out.println(e.getMessage());
	      }

	      // Schließen der Session.

	      sion.close();
	      System.out.println("Session sion closed.");

	      // Schließen der Connection.

	      conn.close();
	      System.out.println("Connection closed.");

	    } catch (IOException e) {
	      e.printStackTrace(System.err);
	      System.exit(2);
	    }
	  }
	}
```


----------



## HoaX (5. Apr 2012)

Es handelt sich ja nicht um ein Problem mit der XML-Ausgabe, sondern um einen fehlenden Wert von SSH, da wäre der Netzwerk bereich passender als XML...

Welche Lib benutzt du für SSH?
Evtl. kann "ssh -v" auch garnicht ausgeführt werden da es nicht im Pfad liegt. Mal den Errorstream ausgeben lassen?

Edith sagt: ssh -V gibt die Version auf dem Errorstream aus, nicht auf der Standardausgabe!


----------



## Knödel0815 (10. Apr 2012)

HoaX hat gesagt.:


> Es handelt sich ja nicht um ein Problem mit der XML-Ausgabe, sondern um einen fehlenden Wert von SSH, da wäre der Netzwerk bereich passender als XML...



Achso dahin... Das tut mir Leid.



HoaX hat gesagt.:


> Welche Lib benutzt du für SSH?


Ich verwende ganymed-ssh2-build210. Ich wusste doch, ich hab eine Info vergessen...



HoaX hat gesagt.:


> Edith sagt: ssh -V gibt die Version auf dem Errorstream aus, nicht auf der Standardausgabe!



Das landet im Errorstream?! Das ist ja interessant. Nungut, daher kann ich mir die Version dann sicher auch holen.
Ok, ich hab versucht, mir den Errorstream ausgeben zu lassen, scheitere dabei aber leider.  (Habe noch nie einen Errorstream ausgelesen und deshalb gegoogelt und versucht das anzupassen. Bestimmt nur ein dummer Fehler, aber ich steh grad aufm Schlauch. Bitte nochmals um Entschuldigung.)

Habe es mit folgendem Code versucht:

```
BufferedReader in = new BufferedReader(new InputStreamReader(ddout.getErrorStream()));
              String s;
              while((s = in.readLine()) != null) {
              System.out.println(s);
              }
```

Aber das getErrorStream() zeigt mir Eclipse als Fehler an. Klicke ich darauf, kommt: "Add cast to 'ddout'". Lasse ich ihn das tun, schreibt er ein (Object) vor das ddout. Allerdings gefällt ihm der Code dann auch nicht besser. (Beim Googlen habe ich den Aufruf des ErrorStreams aber auch nur in Verwendung mit Prozessen gesehen und ich habe ja eine Session. Geht das trotzdem?)
Ich war mir nicht sicher, ob ich ddout für den Errostream nehmen muss und habe es auch mit sion und br4 versucht. Das Ergebnis blieb dasselbe.
Was auch möglich wäre, ist, dass ich es an die falsche Stelle geschrieben habe. Ich habe es unter dem BufferedReader br4 angeordnet. Lag ich damit falsch?


----------



## HoaX (10. Apr 2012)

In deinem Code aus dem ersten Post musst du nur eine Zeile anpassen. 
Der ErrorStream ist genauso wie der normale Ausgabestream vom Typ InputStream, entsprechend arbeitet man damit exakt genauso. Die Zeile oben im Code zu finden überlasse ich dir  aber wenn du drüber nachdenkst, dann wirst du sicherlich verstehen dass du ihn dir irgendwie von der SSH-Verbidung geben lassen musst, und nicht sonst irgendwo herumbasteln. Mir scheint irgendwie du hast den Code oben auch nur irgendwo her kopiert ohne zu verstehen was er macht...
Als Tipp: 60


----------



## Knödel0815 (10. Apr 2012)

Hallo.

Ja, du hast Recht, den hab ich kopiert und versucht anzupassen. Genau verstanden hab ich ihn nicht. (Hab allerdings beim googlen auch kein erklärendes Beispiel gefunden, wie man es für die meisten JAVA-Phrasen findet. Naja, vielleicht hab ich mri auch zu wenig Zeit zum Suchen genommen. Ich hab gerade ein wenig Zeitdruck...)

Mit deiner Hilfe hab ich das jetzt so angepasst:
[JAVA=60]InputStream ddout = new StreamGobbler(sion.getStdout());
	InputStream edout = new StreamGobbler(sion.getErrorStream());[/code]

So meintst du es, oder? (Ich wollte jetzt Testweise mal beide Streams erstellen und dann weitersehen.)
Leider gefällt es Eclipse weiterhin nicht. Nach dem .get bot er es mir den ErrorStream auch nicht in der Auswahl an. 
Also habe ich es wohl doch wieder falsch gemacht?

Naja, ich werde das jetzt aus Zeitgründen lassen müssen (Wie gesagt, stehe unter Zeitdruck, muss eben ohne die SSH-Version gehen.). Vielen lieben Dank noch einmal für deine Hilfe.


----------



## HoaX (10. Apr 2012)

Wie wäre es mit getStderr()? Wäre naheliegent wenn die Standardausgabe getStdout() heißt...


----------



## Knödel0815 (10. Apr 2012)

HoaX hat gesagt.:


> Wie wäre es mit getStderr()? Wäre naheliegent wenn die Standardausgabe getStdout() heißt...



Oooooohhhaaaaa. *an Stirn patsch*
Ach, sorry. Ich steh aufm Schlauch... anscheinend immer.

Und anscheinend gerade auch wieder. Eclipse kriegt ne IOException...

Aber die Ausgabe ist schonmal richtig!!!!! *Freudentanz vollführ*

Kannst du mir bitte bitte nochmal mit der IOException helfen? Jetzt, wo's fast geschafft ist. ^^

Also das ist jetzt der abgeänderte Code:

```
InputStream edout = new StreamGobbler(sion.getStderr());

				// Dies ist die Abfrage der Informationen vom Server.
				// Hier wird der Errorstream ausgelesen und ausgegeben.

					BufferedReader bre = new BufferedReader(new InputStreamReader(
							edout));
					while (true) {
						String linee = bre.readLine();	

					// Die Infrmationen des Servers werden ins XML-File
					// geschrieben.
					
					System.out.println("ssh -V: " + linee);
					out.write("ssh -V: ");
					out.write(linee + "\r\n");

					out.flush(); // Don't forget to flush!
					out.close();

					// Die Aufbereitung der Daten zur Ausgabe in der
					// Console.
					if (linee == null)
						break;
					System.out.println(linee);

				}
```

Und das kommt dann in der Console:

```
Connection successful.
Authentification successful.
Session started.
Hier sind ein paar Informationen zum Host:
ExitCode: null
ssh -V: OpenSSH_5.8p1, OpenSSL 1.0.0c 2 Dec 2010
OpenSSH_5.8p1, OpenSSL 1.0.0c 2 Dec 2010
ssh -V: null
Stream closed
java.io.IOException: Stream closed
	at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:26)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:99)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:116)
	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:203)
	at java.io.Writer.write(Writer.java:140)
	at TestPackage.SSHTest.main(SSHTest.java:90)
Session sion closed.
Connection closed.
```

Fehler im Code bekomme ich jetzt nciht mehr angezeigt. Bei mehrmaligem Durchlaufen zeigt sich, dass die IOException auch nach dem "Session sion closed" oder dem "Connection closed" stehen kann. (Denke, es tut nichts zur Sache, aber falls doch, wollte ich's erwähnt haben.)

Bitte entschuldige, falls das wieder dumme Unfähigkeit meinerseits ist, aber wie gesagt, ich arbeite noch nicht so lange mit Java...


----------



## Knödel0815 (10. Apr 2012)

Achso, im Xml-File steht es jetzt auch richtig. 
Bloß, trotz dass es seine Sache tut, mit IOException weiterarbeiten wär wohl nciht so gut.


----------



## HoaX (10. Apr 2012)

Du rufst scheinbar irgendwo nochmal out.write auf, nachdem du den Writer schon geschlossen hast. Im geposteten Code von eben passt es soweit. Hat soweit nichtsmehr mit SSH zu tun.


----------



## Knödel0815 (10. Apr 2012)

HoaX hat gesagt.:


> Du rufst scheinbar irgendwo nochmal out.write auf, nachdem du den Writer schon geschlossen hast. Im geposteten Code von eben passt es soweit. Hat soweit nichtsmehr mit SSH zu tun.



Das habe ich auch zuerst gedacht. Danach klingt die Fehlermeldung. Aber nach dem if == null break, kommt nur noch die Fehlerverarbeitung. Ich weiß nicht weiter...

Wenns an dem Codestück nicht lag, poste ich nochmal den Ganzen. Wär wahnsinnig lieb, wenn du da nochmal drübersehen könntest.


```
public class SSHTest {
	public static void main(String[] args) {
		// Hier stehen die Daten des Webservers.
		String hostname = "XXX.XXX.XXX.XXX";
		String username = "XXXXXXX";
		String password = "XXXXXXXXXX";

		try {
			// Hier erfolgt die Instanziierung der Verbindung.

			Connection conn = new Connection(hostname);

			// Dies ist die Verbindung. Danach wird eine Erfolgsmeldung
			// ausgegeben.

			conn.connect();
			System.out.println("Connection successful.");

			// Nun erfolgt die Authentifizierung. Dies ist die Variante mit
			// Passwort. (Es wäre auch noch eine Authentifizierung mit PublicKey
			// möglich, aber das ist in diesem Fall zu umständlich.)
			// Es erfolgt eine Ausgabe über Erfolg oder Misserfolg der
			// Authentifizierung.

			boolean isAuthenticated = conn.authenticateWithPassword(username,
					password);

			if (isAuthenticated == false)
				throw new IOException("Authentication failed.");
			else
				System.out.println("Authentification successful.");

			// Hier wird eine Session erstellt, in der dann die Befehle
			// ausgeführt werden können.

			Session sion = conn.openSession();
			System.out.println("Session started.");

			// Als Beispiel erfolgt hier der Befehle "ssh -V".

			sion.execCommand("ssh -V");

			System.out.println("Hier sind ein paar Informationen zum Host:");

			/* Show exit status, if available (otherwise "null") */
			// Ich weiß ehrlich gesagt nicht, was die Passage tut. Irgendein
			// Fehlerabfang?

			System.out.println("ExitCode: " + sion.getExitStatus());

			// Hier erfolgt die Erstellung des OutputStreams.

			try {
				OutputStream fout = new FileOutputStream("SSHTest.xml", true);
				OutputStream bout = new BufferedOutputStream(fout);
				OutputStreamWriter out = new OutputStreamWriter(bout, "8859_1");

				// Hier erfolgt die Erstellung des InputStreams.

				InputStream edout = new StreamGobbler(sion.getStderr());

				// Dies ist die Abfrage der Informationen vom Server.
				// Hier wird der Errorstream ausgelesen und ausgegeben.

					BufferedReader bre = new BufferedReader(new InputStreamReader(
							edout));
					while (true) {
						String linee = bre.readLine();	

					// Die Infrmationen des Servers werden ins XML-File
					// geschrieben.
					
					System.out.println("ssh -V: " + linee);
					out.write("ssh -V: ");
					out.write(linee + "\r\n");

					out.flush(); // Don't forget to flush!
					out.close();

					// Die Aufbereitung der Daten zur Ausgabe in der
					// Console.
					if (linee == null)
						break;
					System.out.println(linee);

				}
			}
			// Die Fehlerverarbeitung für das Schreiben ins XML-File.

			catch (UnsupportedEncodingException e) {
				System.out
						.println("This VM does not support the Latin-1 character set.");
				e.printStackTrace();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
			}

			// Schließen der Session.

			sion.close();
			System.out.println("Session sion closed.");

			// Schließen der Connection.

			conn.close();
			System.out.println("Connection closed.");

		} catch (IOException e) {
			e.printStackTrace(System.err);
			System.exit(2);
		}
	}

}
```

Vielen Dank.


----------



## Knödel0815 (11. Apr 2012)

Hallo nochmal.

Das Problem ist gelöst. Der Vollständigkeit halber und falls mal jemand anderes das Problem hat, wollte ich noch die Lösung posten:

[JAVA=77] out.flush(); // Don't forget to flush!
                    out.close();

                    // Die Aufbereitung der Daten zur Ausgabe in der
                    // Console.
                    if (linee == null)
                        break;
                    System.out.println(linee);[/code]

Das Problem lag an diesen Zeilen. Ich hatte den Stream bereits geschlossen, bevor ich mit dem if bei leeren Zeilen abbrechen wollte.  Diese einfach austauschen.

Bzw ich habe das if jetzt in die while-Schleife mit hinein genommen und es läuft jetzt super. 


```
BufferedReader bre = new BufferedReader(new InputStreamReader(
							edout));
					while (true) {
						String linee = bre.readLine();	
						
						if (linee == null){
							out.close();
							break;
						}
```


----------

