Betrachten Sie den folgenden Code:
String commandf = "ls /etc | grep release";
try {
// Execute the command and wait for it to complete
Process child = Runtime.getRuntime().exec(commandf);
child.waitFor();
// Print the first 16 bytes of its output
InputStream i = child.getInputStream();
byte[] b = new byte[16];
i.read(b, 0, b.length);
System.out.println(new String(b));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
Die Ausgabe des Programms ist:
/etc:
adduser.co
Wenn ich von der Shell aus laufe, funktioniert es natürlich wie erwartet:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
Die Internetseiten sagen mir, dass die brillanten Köpfe, die in der Java-Fabrik arbeiten, die Java produziert, aufgrund der Tatsache, dass das Pipe-Verhalten nicht plattformübergreifend ist, nicht garantieren können, dass Pipes funktionieren.
Wie kann ich das machen?
Ich werde nicht das gesamte Parsen mit Java-Konstrukten durchführen und nicht, grep
und sed
wenn ich die Sprache ändern möchte, muss ich meinen Parsing-Code in dieser Sprache neu schreiben, was absolut unmöglich ist.
Wie kann ich Java dazu bringen, beim Aufrufen von Shell-Befehlen Piping und Umleitung durchzuführen?
java
exec
runtime.exec
Poundifdef
quelle
quelle
command | grep foo
Ihnen ist es viel besser, wenn Sie nurcommand
die Filterung nativ in Java ausführen und durchführen. Dies macht Ihren Code etwas komplexer, aber Sie reduzieren auch den Gesamtressourcenverbrauch und die Angriffsfläche erheblich.Antworten:
Schreiben Sie ein Skript und führen Sie das Skript anstelle separater Befehle aus.
Pipe ist ein Teil der Shell, daher können Sie auch Folgendes tun:
quelle
ls
dhls -lrt
?android
Version sucht , dann benutze/system/bin/sh
stattdessenIch bin unter Linux auf ein ähnliches Problem gestoßen, außer dass es "ps -ef | grep someprocess" war.
Zumindest mit "ls" haben Sie einen sprachunabhängigen (wenn auch langsameren) Java-Ersatz. Z.B.:
Mit "ps" ist es etwas schwieriger, da Java keine API dafür zu haben scheint.
Ich habe gehört, dass Sigar uns möglicherweise helfen kann: https://support.hyperic.com/display/SIGAR/Home
Die einfachste Lösung (wie von Kaj hervorgehoben) besteht jedoch darin, den Befehl piped als String-Array auszuführen. Hier ist der vollständige Code:
Warum das String-Array mit Pipe funktioniert, während ein einzelner String nicht funktioniert, ist eines der Geheimnisse des Universums (insbesondere, wenn Sie den Quellcode nicht gelesen haben). Ich vermute, dass es daran liegt, dass exec, wenn es eine einzelne Zeichenfolge erhält, diese zuerst analysiert (auf eine Weise, die wir nicht mögen). Wenn exec dagegen ein String-Array erhält, wird es einfach an das Betriebssystem weitergeleitet, ohne es zu analysieren.
Eigentlich, wenn wir uns die Zeit nehmen und uns den Quellcode ansehen (unter http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/) Runtime.java # Runtime.exec% 28java.lang.String% 2Cjava.lang.String []% 2Cjava.io.File% 29 ), wir finden, dass genau das passiert:
quelle
Erstellen Sie eine Laufzeit, um jeden Prozess auszuführen. Holen Sie sich den OutputStream von der ersten Laufzeit und kopieren Sie ihn von der zweiten in den InputStream.
quelle
@ Kaj akzeptierte Antwort ist für Linux. Dies ist das Äquivalent für Windows:
quelle