在Java中执行命令而不重定向输出

时间:2014-03-13 00:13:18

标签: java exec file-descriptor

如何从Java程序运行外部命令(通过shell),这样就不会发生重定向,并等待命令结束?我希望外部程序的文件描述符与Java程序的文件描述符相同。特别是我不希望将输出重定向到Java程序正在读取的管道。让Java程序中继输出不是解决方案。

这意味着java.lang.Runtime.exec的简单调用不是解决方案。我假设涉及java.lang.ProcessBuilder,但是如何指定输出和错误流必须与调用Java进程相同?

class A {
    public static void main(String[] args) {
        try {
            ProcessBuilder pb = new ProcessBuilder("echo", "foo");
            /*TODO: pb.out = System.out; pb.err = System.err;*/
            Process p = pb.start();
            p.waitFor();
        } catch (Exception e) {
            System.err.println(e);
            System.exit(1);
        }
    }
}

(这可能是也可能不是正确的做法。)

换句话说,我正在寻找Java的system,但我能找到的只是(大致)popen

以下是中继无法工作的情况示例:如果子进程同时写入stdout和stderr并且Java程序正在中继,那么Java程序无法知道{{1的顺序在子进程中调用。因此,如果两个流最终在同一个文件中,那么来自Java程序的stdout和stderr输出的顺序将明显不同。混合stdout和stderr当然不是解决方案,因为调用者可能希望将它们分开。

虽然我认为这个问题是普遍感兴趣的,但特定于Linux的解决方案可以解决我当前的问题。

3 个答案:

答案 0 :(得分:2)

这是Java 7中引入的ProcessBuilder.redirectError / redirectOutput的意图。使用Redirect.INHERIT将使子进程与Java进程共享stderr / stdout:

class A {
    public static void main(String[] args) {
        try {
            ProcessBuilder builder = new ProcessBuilder("echo", "foo");
            builder.redirectError(ProcessBuilder.Redirect.INHERIT);
            builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
            Process p = builder.start();
            p.waitFor();
        } catch (Exception e) {
            System.err.println(e);
            System.exit(1);
        }
    }
}

答案 1 :(得分:0)

你不能。默认情况下,子进程的所有标准I / O都被重定向到父进程(运行java程序的jvm)。

from the javadoc of the Process class

  

默认情况下,创建的子进程没有自己的终端或   安慰。 所有标准I / O(即stdin,stdout,stderr)   操作将被重定向到父进程,它们可以在那里   通过使用getOutputStream()方法获得的流访问,   getInputStream()和getErrorStream()。父进程使用这些   用于向子进程提供输入和输出的流。因为   某些本机平台仅为标准提供有限的缓冲区大小   输入和输出流,无法及时写入输入流   或者读取子进程的输出流可能会导致子进程   阻止,甚至死锁。

答案 2 :(得分:0)

您可以查看NuProcess项目。免责声明:我写了。它提供了衍生进程的非阻塞I / O.您仍然必须使用Java进行中继(您收到回调),但由于它在Linux的情况下使用epoll(),我希望它能保留底层程序的顺序。只有一个线程是epoll()管道,所以你不会得到任何线程调度订单问题。

我100%的订单将保留在MacOS X或任何BSD变体上,因为它使用了肯定有序的kqueue。无论如何,你可能想要试一试,编码和测试是微不足道的。