如何启动`program1 | program2`使用ProcessBuilder而不使用shell?

时间:2014-02-12 14:49:26

标签: java process pipe io-redirection

我想启动两个程序(如ProcessBuilder),这样第一个程序的输出就是第二个程序的输入。我还想要:

  1. 为了避免使用shell(这样我可以传递带有空格的参数而没有逃避麻烦);
  2. 避免所有数据流入父Java进程并返回(即将单独的线程从一个进程的InputStream复制到另一个进程的OutputStream)。
  3. 如何实现这一目标?

    相关:Building a process pipe with ProcessBuilder in Java 7,但它使用shell ...

1 个答案:

答案 0 :(得分:0)

迟到的答案;但您可以使用命名管道。首先通过mkfifo创建一个。然后在您的Java代码中:

ProcessBuilder pb1 = new ProcessBuilder("gunzip", "-c", "log.gz");
ProcessBuilder pb2 = new ProcessBuilder("grep", "error");

File pipe = new File(NAMED_PIPE_PATH); // NAMED_PIPE_PATH points to what you created via mkfifo

pb1.redirectOutput(ProcessBuilder.Redirect.to(pipe));
pb2.redirectInput(ProcessBuilder.Redirect.from(pipe));

ProcessStartThread pst1 = new ProcessStartThread(pb1);
ProcessStartThread pst2 = new ProcessStartThread(pb2);
pst1.start();
pst2.start();

请注意,ProcessStartThread是一个简单的自定义类,它扩展了Thread,除了在传递的ProcessBuilder实例上调用start()之外,基本上什么都不做。这必须从一个单独的线程完成的原因是ProcessBuilder.start()将挂起,直到命名管道的另一端连接(它需要打开输入/输出以开始执行)。

编辑:这里也是ProcessStartThread课程:

class ProcessStartThread extends Thread {
    private ProcessBuilder procBuilder;
    private Process proc;
    public ProcessStartThread(ProcessBuilder procBuilder) {
        this.procBuilder = procBuilder;
        this.proc = null;
    }
    public void run() {
        try { this.proc = this.procBuilder.start(); } 
        catch ( Exception e ) { e.printStackTrace(); }
    }
    public Process getProcess() {
        return this.proc;
    }
}