Рассмотрим следующий код:
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);
}
Вывод программы:
/etc:
adduser.co
Когда я бегу из оболочки, конечно, все работает как положено:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
Интернет сообщает мне, что из-за того, что поведение конвейера не является кроссплатформенным, блестящие умы, работающие на фабрике Java, производящей Java, не могут гарантировать, что конвейеры работают.
Как я могу это сделать?
Я не собираюсь выполнять весь свой синтаксический анализ, используя конструкции Java, а не grep
и sed
, потому что, если я захочу изменить язык, мне придется переписать код синтаксического анализа на этом языке, что совершенно недопустимо.
Как я могу заставить Java выполнять конвейерную обработку и перенаправление при вызове команд оболочки?
java
exec
runtime.exec
poundifdef
источник
источник
command | grep foo
вам, гораздо лучше просто запуститьcommand
и выполнить фильтрацию непосредственно на Java. Это несколько усложняет ваш код, но вы также значительно сокращаете общее потребление ресурсов и поверхность атаки.Ответы:
Напишите сценарий и выполняйте его вместо отдельных команд.
Труба является частью оболочки, поэтому вы также можете сделать что-то вроде этого:
источник
ls
iels -lrt
?android
здесь версию, то используйте/system/bin/sh
вместоЯ столкнулся с аналогичной проблемой в Linux, за исключением "ps -ef | grep someprocess".
По крайней мере, с «ls» у вас есть независимая от языка (хотя и более медленная) замена Java. Например.:
С «ps» это немного сложнее, потому что Java, похоже, не имеет для этого API.
Я слышал, что Sigar может нам помочь: https://support.hyperic.com/display/SIGAR/Home
Однако самое простое решение (как указал Кай) - выполнить команду, переданную по конвейеру, как массив строк. Вот полный код:
Что касается того, почему массив String работает с конвейером, а отдельная строка - нет ... это одна из загадок вселенной (особенно если вы не читали исходный код). Я подозреваю, что это потому, что когда exec дается одна строка, он сначала разбирает ее (что нам не нравится). Напротив, когда exec предоставляется массив строк, он просто передает его в операционную систему, не анализируя его.
На самом деле, если мы выделим время после напряженного дня и посмотрим на исходный код ( 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 ), мы обнаруживаем, что именно это и происходит:
источник
Создайте среду выполнения для запуска каждого процесса. Получите OutputStream из первой среды выполнения и скопируйте его в InputStream из второй.
источник
@Kaj принятый ответ предназначен для Linux. Это эквивалент для Windows:
источник