2012-01-05 25 views
9

¿Es posible pasar la salida de un proceso creado por ProcessBuilder a otro proceso creado por otro ProcessBuilder? Por ejemplo, si estoy tratando de ejecutar este comando shell:salida de tubería de ProcessBuilder a otro ProcessBuilder

ls | grep build.xml 

cómo debería hacerlo con ProcessBuilder?

como @erdinc sugirió, he intentado esto:

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); 

pero produce diferentes resultados en comparación con cuando corro el guión directamente en la cáscara. ¿Dónde hice mal?

Resuelto: Por favor ver la solución Philipp Wendler

Respuesta

6

El problema con la solución que tiene es que se lea sólo los primeros 1000 bytes desde la salida de ls y los pasa a grep. Como no sabe la cantidad de salida de ls anterior, debe leerla de forma iterativa hasta que se agote.

Aquí es una solución utilizando BufferedReader, que enviará cada línea de salida a 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(); 

Por supuesto, es necesario agregar el control de errores aquí apropiado. Puede omitir el lector y el escritor y pasar las matrices byte[] directamente desde la entrada al flujo de salida si esta solución es demasiado lenta.

Sin embargo, una solución mucho mejor sería no utilizar ls y grep para buscar un archivo en el sistema de archivos, sino utilizar la API Java adecuada. Por ejemplo, si crea un objeto File para el directorio que le interesa, puede usar los diversos métodos listFiles para listar todos los archivos en este directorio. Este método es mucho más fácil, portátil, menos propenso a errores y probablemente más rápido.

+0

¡su solución funciona! gracias Philipp: D De hecho, utilizaré este código para llamar a varias aplicaciones externas, como chasen y moses (herramientas de traducción automática). El ls | El ejemplo de grep solo pretendía simplificar la pregunta, pero gracias por la sugerencia: D Voy a marcar la pregunta resuelta y recomiendo su solución. – ndriks

0

Puede utilizar el método de pasar getInputStream segundo proceso como parámetro. Código de ejemplo;

 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

pero ¿cómo pasar el flujo de entrada "ls" al proceso "grep"? Parece que no puedo encontrar el método setInputStream en proceso. ¿También se puede hacer con ProcessBuilder? – ndriks

+0

He intentado con su solución @erdinc, pero produce resultados diferentes en comparación con ejecutar el comando directamente en shell. He editado la pregunta para mostrar lo que hice. FYI, no estoy tratando de ejecutar grep con el resultado ls como el parámetro, pero estoy tratando de canalizar el resultado de ls al proceso grep. – ndriks

Cuestiones relacionadas