2012-05-10 22 views
8

En otros idiomas (como bash y Python), cuando generamos un proceso secundario, este nuevo proceso heredará stdout y stderr del padre. Esto significa que cualquier salida del proceso secundario se imprimirá en el terminal, así como también la salida del padre.Cómo redirigir el proceso hijo stdout/stderr al proceso principal stdout/stderr en Java?

¿Cómo podemos lograr el mismo comportamiento en Java?

Mi primer intento fue:

proc = Runtime.getRuntime().exec(cmd); 

Pero no va a funcionar. Sobre la base de this answer y this answer, he sustituido el código con:

ProcessBuilder pb = new ProcessBuilder(cmd); 
pb.redirectOutput(System.out); 
pb.redirectError(System.err); 

Pero esto ni siquiera se compila, ya que los argumentos son incompatibles con los parámetros del método esperados.

Respuesta

13

Necesita leer los flujos de salida y error del proceso que ha creado y escribir el resultado en el lugar que desee (en su caso, System.out y System.err).

Editar. La respuesta anterior es correcta para Java < 7. A partir del 7 de la javadoc que parece ser posible en vez llamar

processBuilder.redirectOutput(Redirect.INHERIT) 
+1

¿Quiere decir que necesito implementar un bucle que simplemente sigue leyendo de una secuencia y escribiendo en otra? Lo siento, no es factible. Demasiado trabajo (probablemente requiere ejecutar un nuevo hilo, e introduce muchos puntos de posibles errores). –

+2

Puede o no ser esto lo que se solía requerir. Acabo de comprobar la API de Java 7 y parece que se ha solucionado: ahora puede llamar a redirectOutput pasando por Redirect.INHERIT que busca lograr lo que desea. – henry

1

Es ciertamente posible. La tarea Ant Java hace esto cuando fork se establece como verdadero. No recuerdo todos los detalles, pero con una mirada rápida parece que la mayoría de la magia está en PumpStreamHandler. Puede tratar de encontrar algo de inspiración a partir de eso.

+1

En realidad es más fácil que eso, pero solo es aplicable en 1.7, que pareces estar usando ya que estás usando ProcessBuilder.redirectOutput() es hacer pb.redirectOutput (Redirect.INHERIT). Aunque nunca lo hice yo mismo. – asudell

3

Esto no es tan malo. Al principio me dije "fácil", entonces me di cuenta de que había tenido que codificar el InputStreamConsumer:

public static class InputStreamConsumer extends Thread { 

    private InputStream is; 

    public InputStreamConsumer(InputStream is) { 
     this.is = is; 
    } 

    @Override 
    public void run() { 

     try { 
      int value = -1; 
      while ((value = is.read()) != -1) { 
       System.out.print((char)value); 
      } 
     } catch (IOException exp) { 
      exp.printStackTrace(); 
     } 
    } 
} 

private void captureOutput(Process p) { 

    InputStreamConsumer stdout; 
    InputStreamConsumer errout; 

    errout = new InputStreamConsumer(p.getErrorStream()); 
    stdout = new InputStreamConsumer(p.getInputStream()); 
    errout.start(); 
    stdout.start(); 
} 

.... ejecuta dentro de algo así como ...

ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/D", "/C", myCommand, parm, parm...); 
    try { 
     System.out.println("Start "+myCommand); 
     Process myProcess = pb.start(); 
     captureOutput(myProcess); 

     int returnCode = myProcess.waitFor(); 
     System.out.println("myProcess: return code : "+returnCode); 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
+0

Los otros no funcionaron para mí, excepto en el IDE. Este lo hizo, gracias. – Steve

+1

Se ve bien, pero ¿tenemos que usar dicho código auto implementado? No hay soporte en Java para redirigir STDERR a STDOUT y luego leer la combinación de ellos de un flujo de entrada? – SomethingSomething

Cuestiones relacionadas