Rozważ następujący kod:
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);
}
Wynik programu to:
/etc:
adduser.co
Kiedy biegnę z powłoki, to oczywiście działa zgodnie z oczekiwaniami:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
Internety mówią mi, że ze względu na fakt, że zachowanie potoków nie jest wieloplatformowe, genialne umysły pracujące w fabryce Javy produkującej Javę nie mogą zagwarantować, że potoki będą działać.
W jaki sposób mogę to zrobić?
Nie zamierzam wykonywać całego analizowania przy użyciu konstrukcji Java zamiast grep
ised
, bo jeśli chcę zmienić język, będę zmuszony do ponownego napisać kod parsowania w tym języku, który jest całkowicie nie-Go.
Jak sprawić, by Java wykonywała potoki i przekierowywanie podczas wywoływania poleceń powłoki?
java
exec
runtime.exec
poundifdef
źródło
źródło
command | grep foo
ty, znacznie lepiej jest po prostu uruchomićcommand
i wykonać filtrowanie natywnie w Javie. To sprawia, że twój kod jest nieco bardziej złożony, ale także znacznie zmniejszasz ogólne zużycie zasobów i powierzchnię ataku.Odpowiedzi:
Napisz skrypt i wykonaj go zamiast oddzielnych poleceń.
Rura jest częścią powłoki, więc możesz też zrobić coś takiego:
źródło
ls
IEls -lrt
?android
tutaj wersji, to użyj/system/bin/sh
zamiast tegoNapotkałem podobny problem w Linuksie, z wyjątkiem tego, że był to „ps -ef | grep jakiś proces”.
Przynajmniej z "ls" masz niezależną od języka (choć wolniejszą) zamiennik Javy. Na przykład.:
Z "ps" jest trochę trudniej, ponieważ Java nie ma do tego API.
Słyszałem, że Sigar może nam pomóc: https://support.hyperic.com/display/SIGAR/Home
Jednak najprostszym rozwiązaniem (jak wskazał Kaj) jest wykonanie polecenia potokowego jako tablicy łańcuchowej. Oto pełny kod:
Co do tego, dlaczego tablica String działa z potokiem, podczas gdy pojedynczy ciąg nie ... to jedna z tajemnic wszechświata (zwłaszcza jeśli nie czytałeś kodu źródłowego). Podejrzewam, że dzieje się tak dlatego, że gdy exec otrzymuje pojedynczy ciąg, najpierw go analizuje (w sposób, który nam się nie podoba). W przeciwieństwie do tego, gdy exec otrzymuje tablicę ciągów, po prostu przekazuje ją do systemu operacyjnego bez jej analizowania.
Właściwie, jeśli poświęcimy trochę czasu z pracowitego dnia i spojrzymy na kod źródłowy (na 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 ), okazuje się, że dokładnie to się dzieje:
źródło
Utwórz środowisko wykonawcze, aby uruchomić każdy proces. Pobierz OutputStream z pierwszego Runtime i skopiuj go do InputStream z drugiego.
źródło
@Kaj zaakceptowana odpowiedź dotyczy linuxa. To jest odpowiednik dla systemu Windows:
źródło