【问题标题】:piping output of ProcessBuilder to another ProcessBuilderProcessBuilder 的管道输出到另一个 ProcessBuilder
【发布时间】:2012-01-05 20:44:17
【问题描述】:

是否可以将 ProcessBuilder 创建的一个进程的输出传递给另一个 ProcessBuilder 创建的另一个进程?例如,如果我试图执行这个 shell 命令:

ls | grep build.xml

我应该如何使用 ProcessBuilder?

正如@erdinc 建议的那样,我尝试了这个:

Process process = Runtime.getRuntime().exec("ls");
InputStream is = process.getInputStream();
byte[] buf = new byte[1000];
is.read(buf);
String parameter = new String(buf);
System.out.println("grep build " + parameter);

Process proc2 = Runtime.getRuntime().exec("grep build " + parameter);
InputStream is2 = proc2.getInputStream();
byte[] buf2 = new byte[1000];
is2.read(buf2);
String result = new String(buf2);
System.out.println("proc2 result: " + result);

但与我直接在 shell 中运行脚本相比,它会产生不同的结果。我哪里做错了?

已解决:请参阅 Philipp Wendler 解决方案

【问题讨论】:

    标签: java runtime.exec


    【解决方案1】:

    您的解决方案的问题是它仅从 ls 的输出中读取前 1000 个字节并将它们传递给 grep。由于之前不知道ls的输出量,所以需要反复读取,直到用完为止。

    这是一个使用 BufferedReader 的解决方案,它将每行输出发送到 grep:

    Process lsProcess = Runtime.getRuntime().exec("ls");
    BufferedReader lsOutput = new BufferedReader(new InputStreamReader(lsProcess.getInputStream()));
    Process grepProcess = Runtime.getRuntime().exec("grep build.xml");
    BufferedWriter grepInput = new BufferedWriter(new OutputStreamWriter(grepProcess.getOutputStream()));
    
    String line;
    // read each line from ls until there are no more
    while ((line = lsOutput.readLine()) != null) {
        // and send them to grep
        grepInput.write(line);
        grepInput.newLine();
    }
    
    // send end-of-file signal to grep so it will terminate itself
    grepInput.close();
    

    当然,您需要在此处添加适当的错误处理。 如果此解决方案太慢,您可以省略 Reader 和 Writer,直接将 byte[] 数组从输入传递到输出流。

    但是,更好的解决方案不是使用 ls 和 grep 在文件系统中查找文件,而是使用适当的 Java API。例如,如果您为您感兴趣的目录创建一个File 对象,您可以使用其上的各种listFiles 方法来列出该目录中的所有文件。这种方法更简单、便携、不易出错并且可能更快。

    【讨论】:

    • 您的解决方案有效!谢谢 Philipp :D 我实际上将使用这段代码来调用几个外部应用程序,例如chasen 和 moses(机器翻译工具)。 ls | grep 示例仅用于简化问题,但感谢您的建议:D 我将标记问题已解决并为您的解决方案投票。
    【解决方案2】:

    您可以使用 getInputStream 方法而不是作为参数传递第二个 Process。 示例代码;

            process = Runtime.getRuntime().exec("ls");
            InputStream is = process.getInputStream();
            byte[] buf = new byte[1000];
            is.read(buf);
            String parameter = new String(buf);
            System.out.println(parameter);
            Runtime.getRuntime().exec("grep build.xml " + parameter);
    

    【讨论】:

    • 但是如何将“ls”输入流传递给“grep”进程?我似乎在 Process 中找不到方法 setInputStream。也可以用ProcessBuilder来完成吗?
    • 我已经尝试过您的解决方案@erdinc,但与直接在 shell 中运行命令相比,它会产生不同的结果。我已经编辑了这个问题来展示我做了什么。仅供参考,我不是试图以 ls 结果作为参数运行 grep,但我试图将 ls 的结果通过管道传递给 grep 进程。
    猜你喜欢
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-16
    相关资源
    最近更新 更多