exec在Java中执行命令而不重定向输出
如何从Java程序运行外部命令(通过shell),以便不发生重定向,并等待命令结束?我希望外部程序的文件描述符与Java程序的文件描述符相同。特别是我不希望将输出重定向到Java程序正在读取的管道。让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程序无法知道子进程中write
调用的顺序。因此,如果两个流最终位于同一个文件中,那么Java程序在stdout和stderr上的输出顺序将明显不同。混合使用stdout和stderr当然不是一个解决方案,因为调用方可能希望将它们分开
虽然我认为这个问题是大家都感兴趣的,但Linux特定的解决方案可以解决我眼前的问题
# 1 楼答案
您可以看看NuProcess项目。免责声明:是我写的。它提供来自派生进程的非阻塞I/O。您仍然需要在Java中进行中继(您会收到回调),但因为它在Linux中使用epoll(),所以我希望它能够保持底层程序的顺序。只有一个线程正在对管道进行epoll(),因此不会出现任何线程调度顺序问题
我敢肯定,MacOS X或任何BSD变体都会100%保留订单,因为它使用的是一个绝对有序的kqueue。无论如何,您可能想尝试一下,编写代码和测试都很简单
# 2 楼答案
这就是在Java7中引入的^{} /^{} 的意图。使用^{} 将使子进程与Java进程共享stderr/stdout:
# 3 楼答案
不能。默认情况下,子进程的所有标准I/O都重定向到父进程(运行java程序的jvm)
from the javadoc of the Process class: