2012-01-05 4 views
9

Возможно ли передать результат одного процесса, созданного ProcessBuilder, другому процессу, созданному другим ProcessBuilder? Например, если я пытаюсь выполнить эту команду оболочки:вывод трубопровода ProcessBuilder в другой ProcessBuilder

ls | grep build.xml 

как я должен делать это с ProcessBuilder?

, как @erdinc предложил, я попытался это:

Process process = Runtime.getRuntime().exec("ls"); 
InputStream is = process.getInputStream(); 
byte[] buf = new byte[1000]; 
is.read(buf); 
String parameter = new String(buf); 
System.out.println("grep build " + parameter); 

Process proc2 = Runtime.getRuntime().exec("grep build " + parameter); 
InputStream is2 = proc2.getInputStream(); 
byte[] buf2 = new byte[1000]; 
is2.read(buf2); 
String result = new String(buf2); 
System.out.println("proc2 result: " + result); 

но он производит другой результат сравнения, когда я запустить скрипт непосредственно в оболочке. Где я ошибался?

Решено: Пожалуйста, смотрите Philipp Wendler решение

ответ

6

Проблема с решением у вас есть то, что он читает только первые 1000 байт из выходного логинсервера и передает их Grep. Поскольку вы не знаете объем вывода от ls before, вам нужно прочитать его итеративно, пока он не будет исчерпан.

Вот решение с использованием BufferedReader, который будет посылать каждую строку вывода на Grep:

Process lsProcess = Runtime.getRuntime().exec("ls"); 
BufferedReader lsOutput = new BufferedReader(new InputStreamReader(lsProcess.getInputStream())); 
Process grepProcess = Runtime.getRuntime().exec("grep build.xml"); 
BufferedWriter grepInput = new BufferedWriter(new OutputStreamWriter(grepProcess.getOutputStream())); 

String line; 
// read each line from ls until there are no more 
while ((line = lsOutput.readLine()) != null) { 
    // and send them to grep 
    grepInput.write(line); 
    grepInput.newLine(); 
} 

// send end-of-file signal to grep so it will terminate itself 
grepInput.close(); 

, конечно, нужно добавить соответствующую обработку ошибок здесь. Вы можете опустить Reader и Writer и передать byte[] массивы непосредственно из входа в выходной поток, если это решение слишком медленное.

Однако гораздо лучшим решением было бы не использовать ls и grep для поиска файла в файловой системе, а для использования соответствующего Java API. Например, если вы создаете объект File для интересующего вас каталога, вы можете использовать различные методы listFiles, чтобы перечислять все файлы в этом каталоге. Этот метод намного проще, портативен, менее подвержен ошибкам и, вероятно, быстрее.

+0

Ваше решение работает! спасибо Филипп: D Я действительно буду использовать этот код для вызова нескольких внешних приложений, таких как chasen и moses (инструменты машинного перевода). Ls | Пример grep предназначен только для упрощения вопроса, но спасибо за предложение: D Я постараюсь решить вопрос и решить ваше решение. – ndriks

0

Вы можете использовать метод getInputStream, чем передать в качестве параметра второго процесса. Пример кода;

 process = Runtime.getRuntime().exec("ls"); 
     InputStream is = process.getInputStream(); 
     byte[] buf = new byte[1000]; 
     is.read(buf); 
     String parameter = new String(buf); 
     System.out.println(parameter); 
     Runtime.getRuntime().exec("grep build.xml " + parameter); 
+0

но как передать входной поток «ls» в процесс «grep»? Я не могу найти метод setInputStream в процессе. Также это можно сделать с помощью ProcessBuilder? – ndriks

+0

Я пробовал ваше решение @erdinc, но он производит разные результаты, сравнивая с запуском команды непосредственно в оболочке. Я отредактировал вопрос, чтобы показать, что я сделал. FYI, я не пытаюсь запустить grep с результатом ls в качестве параметра, но я пытаюсь передать результат ls в процесс grep. – ndriks