Java: ¿hay una manera de ejecutar un comando del sistema e imprimir la salida durante la ejecución?

Tengo una secuencia de comandos de python y se tarda mucho tiempo en finalizar. Me gustaría ejecutarlo desde Java, pero también mostrar la salida del script mientras se está ejecutando, para que pueda saber si se está ejecutando correctamente.

Busqué y solo encontré ejemplos en los que emitimos el resultado una vez que el comando del sistema ha finalizado, en lugar de hacerlo durante su ejecución.

¿Alguna forma de hacerlo mientras se ejecuta el script?

Esto es lo que tengo

public void doSomething() throws IOException { String[] callAndArgs = {"python", "/hi.py"}; Process p = Runtime.getRuntime().exec(callAndArgs); BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); String s; while ((s = stdInput.readLine()) != null) { System.out.println(s); } while ((s = stdError.readLine()) != null) { System.out.println(s); } } 

Me las arreglé para hacerlo funcionar así (nota que requiere java7):

 package test; import java.lang.ProcessBuilder.Redirect; public class Test { public static void main(String... args) throws Exception { ProcessBuilder pb = new ProcessBuilder("python","/home/foobar/Programming/test/src/test/test.py"); pb.redirectOutput(Redirect.INHERIT); Process p = pb.start(); p.waitFor(); } } 

python (note que lo descargo en python para que funcione con sys.stdout.flush ())

 import time,sys c =0 while c<=50: time.sleep(1) print("----") c = c +1 sys.stdout.flush() 

Tenga en cuenta que si no desea descargar un bucle, puede usar esto:

 ProcessBuilder pb = new ProcessBuilder("python","-u","/home/foobar/Programming/NetBeansProjects/test/src/test/test.py"); 

Redirigir.

Indica que el origen o destino de E / S de subproceso será el mismo que el del proceso actual. Este es el comportamiento normal de la mayoría de los intérpretes de comandos del sistema operativo (shells).

Busqué y solo encontré ejemplos en los que emitimos el resultado una vez que el comando del sistema ha finalizado, en lugar de hacerlo durante su ejecución.

Eso es raro, porque su ejemplo debería ser volcar la salida mientras se ejecuta el comando.

En lugar de usar BufferedReader , puede intentar leer directamente desde InputStream ya que las condiciones requeridas para readLine podrían no cumplirse hasta después de que el proceso finalice.

También recomendaría que use un ProcessBuilder sobre Process directamente, ya que, aparte de todo lo demás, le permite redirigir la salida de la secuencia de error a la secuencia de entrada, lo que le permite leer solo una secuencia en lugar de dos …

Esto también podría ser un problema con Python y la forma en que elimina los búferes de salida …

Por ejemplo, en lugar de esperar a que el BufferedReader decida cuándo volver, intente imprimir cada carácter del flujo a medida que se produce / se informa

  ProcessBuilder pb = new ProcessBuilder("test.py"); pb.redirectError(); Process p = pb.start(); InputStream is = null; try { is = p.getInputStream(); int in = -1; while ((in = is.read()) != -1) { System.out.print((char)in); } } finally { try { is.close(); } catch (Exception e) { } } 

Actualizar

Al leer un poco, Python parece estar guardándolo antes de enviarlo a la salida estándar. No creo que puedas arreglar esto en el lado de Java, pero necesito modificar la forma en que se ejecuta Python o el script funciona.

Consulte ¿Cómo vaciar la salida de impresión de Python? para más detalles

No uses #readLine como condicional en tu bucle while. En su lugar, envuelva su inputStream en un escáner y use #hasNextLine ()

  Scanner in = new Scanner(p.getInputStream()); while (in.hasNextLine()) { System.out.println(in.nextLine()); } 

Sospecho que estás escribiendo a stderr, que no puedes ver porque estás bloqueando en la entrada estándar. Use un ProcessBuilder en lugar de hacer exec . De esta manera, puede redireccionar stderr y stdin a una sola secuencia.

Aquí hay un ejemplo:

 import java.io.*; public class Test { public static void main(String... args) throws IOException { ProcessBuilder pb = new ProcessBuilder("test.py"); pb.redirectErrorStream(true); Process proc = pb.start(); Reader reader = new InputStreamReader(proc.getInputStream()); BufferedReader bf = new BufferedReader(reader); String s; while ((s = bf.readLine()) != null) { System.out.println(s); } } } 

Alternativamente, puedes generar hilos para leer desde stdin / stderr respectivamente.

Otra cosa a buscar es el búfer de salida por python. Puedes ver si esta es la causa haciendo:

 import sys sys.stdout.flush() 

despues de escribir a stdout