如何从Java程序运行外部命令(通过shell),以便不发生重定向,并等待命令结束?我希望外部程序的文件描述符与Java程序的文件描述符相同。特别是我不希望输出被重定向到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
。
这里是哪里中继无法工作情况的一个例子:如果子进程写到标准输出和标准错误和Java程序中继,那么Java程序没有办法知道在子的write
调用的顺序。因此,如果两个流最终在同一个文件中,那么来自Java程序的stdout和stderr上的输出顺序将明显不同。混合stdout和stderr当然不是一个解决方案,因为调用者可能希望将它们分开。
虽然我认为这个问题很普遍,但Linux特有的解决方案可以解决我眼前的问题。
您应该使用['Process.getInputStream( )'](http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html#getInputStream())。您需要从sysout和err中读取两个独立线程中的进程,否则它们的缓冲区可能会被填满,进程将被阻止。 [This](http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html)是一篇关于从Java运行外部进程的优秀文章。就我个人而言,我会使用[Apache commons exec](http://commons.apache.org/proper/commons-exec/)来节省自己的一些痛苦。 –
@BoristheSpider我不想从Java程序中读取子进程的输出。 – Gilles
如果您不想中继输出,并且您满足于坚持特定于平台的解决方案,那么您可以使用jni调用一个包装器,然后调用该平台的本地系统()函数。但是,请记住system()是阻塞的,所以您可能需要从它自己的线程中完成此操作。这可能会遇到各种exec()相关的复杂问题,具体取决于JVM如何设置。另一个选择是找出当前终端是什么,并在子进程中打开stdout,可能使用中介。 –