2012-05-10 8 views
8

In anderen Sprachen (wie Bash und Python), wenn wir einen untergeordneten Prozess spawnen, erbt dieser neue Prozess die Stdout und Stderr von der übergeordneten. Dies bedeutet, dass alle Ausgaben des untergeordneten Prozesses an das Terminal sowie die Ausgabe des übergeordneten Prozesses gedruckt werden.Wie Umleitung Child-Prozess stdout/stderr auf den Hauptprozess stdout/stderr in Java?

Wie können wir das gleiche Verhalten in Java erreichen?

Mein erster Versuch war:

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

Aber es wird nicht funktionieren. Basierend auf this answer und this answer, habe ich den Code mit Fassung:

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

Aber nicht einmal kompilieren, da die Argumente mit dem erwarteten Methodenparameter nicht kompatibel sind.

Antwort

13

Sie müssen die Ausgabe- und Fehlerströme des von Ihnen erstellten Prozesses lesen und die Ausgabe an die Stelle schreiben, an die sie gehen soll (in Ihrem Fall System.out und System.err).

Bearbeiten. Die obige Antwort ist richtig für Java < 7. Wie von 7 aus dem javadoc es stattdessen möglich sein, sieht

zu nennen
processBuilder.redirectOutput(Redirect.INHERIT) 
+1

Sie meinen, ich muss eine Schleife implementieren, die nur aus einem Stream liest und in einem anderen schreibt? Entschuldigung, nicht machbar. Zu viel Arbeit (erfordert wahrscheinlich, in einem neuen Thread zu laufen, und es bringt viele Punkte möglicher Fehler ein). –

+2

Machbar oder nicht, was früher benötigt wurde. Ich habe gerade die Java 7 API überprüft und es sieht so aus, als ob es adressiert wurde - Sie können jetzt redirectOutput in Redirect.INHERIT übergeben, das aussieht, um zu erreichen, was Sie wollen. – henry

1

Es ist sicherlich möglich. Die Ant-Java-Aufgabe tut dies, wenn fork auf true gesetzt ist. Ich erinnere mich nicht an alle Details, aber bei einem schnellen Blick scheint es, dass der Großteil der Magie in PumpStreamHandler ist. Sie könnten versuchen, etwas Inspiration daraus zu finden.

+1

Eigentlich einfacher als das, aber nur anwendbar in 1.7, die Sie zu verwenden scheinen, seit Sie ProcessBuilder.redirectOutput() verwenden, ist es pb.redirectOutput (Redirect.INHERIT). Obwohl ich das selbst nie gemacht habe. – asudell

3

Das ist nicht so schlimm. Ich sagte zunächst „easy“, dann merkte ich, ich hätte, würde die InputStreamConsumer kodieren:

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

.... innerhalb von etwas läuft wie ...

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

Die anderen funktionierten nicht für mich, außer in der IDE. Dieser hat, danke. – Steve

+1

Sieht gut aus - aber müssen wir solchen selbst implementierten Code verwenden? Es gibt keine Unterstützung in Java, STDERR in STDOUT umzuleiten und dann die Kombination von ihnen aus einem Eingabestream zu lesen? – SomethingSomething