Erstens würde ich empfehlen, die Leitung zu ersetzen
Process process = Runtime.getRuntime ().exec ("/bin/bash");
mit den Zeilen
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder ist neu in Java 5 und erleichtert das Ausführen externer Prozesse. Meiner Meinung nach besteht die wichtigste Verbesserung Runtime.getRuntime().exec()
darin, dass Sie den Standardfehler des untergeordneten Prozesses in seine Standardausgabe umleiten können. Dies bedeutet, dass Sie nur einen InputStream
zum Lesen haben. Zuvor mussten zwei separate Threads vorhanden sein, ein Lesevorgang von stdout
und ein Lesevorgang von stderr
, um zu vermeiden, dass der Standardfehlerpuffer gefüllt wird, während der Standardausgabepuffer leer ist (wodurch der untergeordnete Prozess hängen bleibt), oder umgekehrt.
Als nächstes die Schleifen (von denen Sie zwei haben)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Beenden Sie reader
das Programm nur, wenn das , das aus der Standardausgabe des Prozesses liest, das Dateiende zurückgibt. Dies geschieht nur, wenn der bash
Prozess beendet wird. Es wird kein Dateiende zurückgegeben, wenn derzeit keine Ausgabe mehr vom Prozess erfolgt. Stattdessen wartet es auf die nächste Ausgabezeile des Prozesses und kehrt erst zurück, wenn es diese nächste Zeile hat.
Da Sie zwei Eingabezeilen an den Prozess senden, bevor Sie diese Schleife erreichen, bleibt die erste dieser beiden Schleifen hängen, wenn der Prozess nach diesen beiden Eingabezeilen nicht beendet wurde. Es wird dort sitzen und darauf warten, dass eine andere Zeile gelesen wird, aber es wird nie eine andere Zeile geben, in der es gelesen werden kann.
Ich Ihren Quellcode kompiliert (Ich bin auf Windows zur Zeit, so dass ich ersetzt /bin/bash
mit cmd.exe
, aber die Prinzipien sollten gleich sein), und ich stellte fest , dass:
- Nach dem Eingeben von zwei Zeilen wird die Ausgabe der ersten beiden Befehle angezeigt, aber dann hängt das Programm.
- Wenn ich beispielsweise tippe
echo test
und dann exit
, verlässt das Programm die erste Schleife seit dem cmd.exe
Beenden des Prozesses. Das Programm fordert dann eine weitere Eingabezeile an (die ignoriert wird), überspringt direkt die zweite Schleife, da der untergeordnete Prozess bereits beendet wurde, und beendet sich dann selbst.
- Wenn ich
exit
dann echo test
tippe, erhalte ich eine IOException, die sich über das Schließen einer Pipe beschwert. Dies ist zu erwarten - die erste Eingabezeile hat den Prozess beendet, und die zweite Zeile kann nirgendwo gesendet werden.
Ich habe in einem Programm, an dem ich früher gearbeitet habe, einen Trick gesehen, der etwas Ähnliches bewirkt, wie Sie es zu wollen scheinen. Dieses Programm behielt eine Reihe von Shells bei, führte darin Befehle aus und las die Ausgabe dieser Befehle. Der verwendete Trick bestand darin, immer eine "magische" Zeile zu schreiben, die das Ende der Ausgabe des Shell-Befehls markiert, und damit zu bestimmen, wann die Ausgabe des an die Shell gesendeten Befehls beendet war.
Ich habe Ihren Code genommen und alles nach der zugewiesenen Zeile writer
durch die folgende Schleife ersetzt:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
// Putting 'exit' amongst the echo --EOF--s below doesn't work.
writer.write("exit\n");
} else {
writer.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
}
writer.flush();
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
System.out.println ("Stdout: " + line);
line = reader.readLine();
}
if (line == null) {
break;
}
}
Danach konnte ich zuverlässig einige Befehle ausführen und die Ausgabe von jedem einzeln an mich zurücksenden lassen.
Die beiden echo --EOF--
Befehle in der an die Shell gesendeten Zeile dienen dazu, sicherzustellen, dass die Ausgabe des Befehls --EOF--
auch im Ergebnis eines Befehlsfehlers beendet wird.
Natürlich hat dieser Ansatz seine Grenzen. Diese Einschränkungen umfassen:
- Wenn ich einen Befehl eingebe, der auf Benutzereingaben wartet (z. B. eine andere Shell), scheint das Programm zu hängen.
- Es wird davon ausgegangen, dass jeder von der Shell ausgeführte Prozess seine Ausgabe mit einem Zeilenumbruch beendet.
- Es wird etwas verwirrt, wenn der von der Shell ausgeführte Befehl zufällig eine Zeile ausschreibt
--EOF--
.
bash
meldet einen Syntaxfehler und wird beendet, wenn Sie Text mit einem nicht übereinstimmenden Text eingeben )
.
Diese Punkte sind für Sie möglicherweise nicht von Bedeutung, wenn sich das, was Sie als geplante Aufgabe ausführen möchten, auf einen Befehl oder einen kleinen Satz von Befehlen beschränkt, die sich niemals so pathologisch verhalten werden.
BEARBEITEN : Verbessern Sie das Exit-Handling und andere kleinere Änderungen, nachdem Sie dies unter Linux ausgeführt haben.