web-dev-qa-db-ja.com

プロセス出力をstdoutにリダイレクトする

Groovyプログラム内からfoo.batを実行し、結果のプロセスの出力をstdoutにリダイレクトしたいと思います。 JavaまたはGroovyコード例のいずれかで問題ありません。

foo.batの実行には数分かかる場合があり、大量の出力が生成されるため、すべての出力を一度に確認する前にプロセスが完了するまで待つ必要はなく、生成後すぐに出力を確認したいと思います。

25
Dónal

これは、実行されたプログラムが生成するすべての出力を読み取り、それを独自のstdoutに表示するクラスを使用します。

class StreamGobbler extends Thread {
    InputStream is;

    // reads everything from is until empty. 
    StreamGobbler(InputStream is) {
        this.is = is;
    }

    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null)
                System.out.println(line);    
        } catch (IOException ioe) {
            ioe.printStackTrace();  
        }
    }
}

Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
//output both stdout and stderr data from proc to stdout of this process
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream());
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream());
errorGobbler.start();
outputGobbler.start();
proc.waitFor();
34
jitter

InheritIO()メソッドを使用して、すべてのストリームを標準出力にリダイレクトするのは簡単です。これにより、このコマンドを実行しているプロセスのstdoutに出力が出力されます。

ProcessBuilder pb = new ProcessBuilder("command", "argument");
pb.directory(new File(<directory from where you want to run the command>));
pb.inheritIO();
Process p = pb.start();
p.waitFor();

他にも以下のような方法があります。これらの個別のメソッドは、必要なストリームのみをリダイレクトするのに役立ちます。

    pb.redirectInput(Redirect.INHERIT)
    pb.redirectOutput(Redirect.INHERIT)
    pb.redirectError(Redirect.INHERIT)
56
Pandurang Patil

より多くのGroovyとより少ないJavaでこれを行うことを検討している場合、これにより、発生時に各行が出力されます。

def cmd = "./longRunningProcess"

def process = cmd.execute()
process.in.eachLine { line -> println line }

または、stdoutとstderrの両方を表示したい場合

def cmd = "./longRunningProcess"

def process = cmd.execute()
process.waitForProcessOutput( System.out, System.err )
7
gMale

次のGroovyコードはfoo.batを実行し、出力をstdoutに送信します。

println "foo.bat".execute().text
4

単純なコマンドの出力を取得しようとしているだけの場合は、少し簡単な方法を示します。並列処理したい場合や、コマンドがstdinを取得したりstderrを生成したりする場合は、ジッターのようなスレッドを使用する必要があります。

大量の出力を取得している場合は、バッファコピー( this など)を使用します。

import Java.io.*;
public class test {
  static void copy(InputStream in, OutputStream out) throws IOException {
    while (true) {
      int c = in.read();
      if (c == -1) break;
      out.write((char)c);
    }
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    String cmd = "echo foo";
    Process p = Runtime.getRuntime().exec(cmd);
    copy(p.getInputStream(), System.out);
    p.waitFor();
  }
}
4
Keith Randall

それを達成するための非同期の方法。

void inputStreamToOutputStream(final InputStream inputStream, final OutputStream out) {
    Thread t = new Thread(new Runnable() {

        public void run() {
            try {
                int d;
                while ((d = inputStream.read()) != -1) {
                    out.write(d);
                }
            } catch (IOException ex) {
                //TODO make a callback on exception.
            }
        }
    });
    t.setDaemon(true);
    t.start();
}

{
    Process p = ...;
    inputStreamToOutputStream(p.getErrorStream(), System.out);
    inputStreamToOutputStream(p.getInputStream(), System.out);
}
2
Daniel De León

VerboseProcessjcabi-log から:

String output = new VerboseProcess(new ProcessBuilder("foo.bat")).stdout();
0
yegor256