为什么这个Java进程在作为子进程运行bash之后会挂起?
如果我从bash编译并运行以下Java程序:为什么这个Java进程在作为子进程运行bash之后会挂起?,java,bash,process,Java,Bash,Process,如果我从bash编译并运行以下Java程序: public class BashSuspend { public static void main(String[] args) throws Exception { Process process = new ProcessBuilder("bash -i -c ls".split(" ")) .redirectInput(ProcessBuilder.Redirect.INHERIT)
public class BashSuspend {
public static void main(String[] args) throws Exception {
Process process = new ProcessBuilder("bash -i -c ls".split(" "))
.redirectInput(ProcessBuilder.Redirect.INHERIT)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.redirectError(ProcessBuilder.Redirect.INHERIT).start();
process.waitFor();
System.in.read();
}
}
我看到一些奇怪的行为:
matt@Overmind:~/bash-suspend$ java BashSuspend
BashSuspend.class BashSuspend.java
[1]+ Stopped java BashSuspend
matt@Overmind:~/bash-suspend$
为什么Java进程在作为子进程运行bash之后会挂起
(我正在Ubuntu 15.10上运行openjdk版本“1.8.0_66-internal”。您的程序正在等待输入,这只有在前台运行时才能执行
我不会等待您忽略的输入,而是将其删除或使用另一种方法。由于使用了以下内容,您的
[1]+将被停止:
bash -i
它正在交互模式下运行bash
。删除-i
选项以修复此问题:
new ProcessBuilder("bash -c ls".split(" "))
根据曼巴什
:
-i If the -i option is present, the shell is interactive.
您还需要注释掉System.in.read()代码>以避免程序继续运行(它只是在等待输入)
仅需在您停止错误后向我的答案添加更多信息,您可以运行:
jobs -l
要列出后台运行的作业,它将显示如下内容:
[1]+ 71598 Stopped (tty input): 21 java BashSuspend
这是由于您使用了System.in.read()
正在交互shell中等待输入,该shell没有附加tty
,因此它被停止。程序应始终在前台运行。它可能在等待子进程完成或从stdin读取时阻塞,但这与挂起不同。我感兴趣的是为什么运行“bash-I”会导致java进程挂起。因为ProcessBuilder
并不是真正运行交互式bash
。交互式bash
是指您通常使用的bash
登录shell,它附带了tty
,而这里我们没有任何tty
附件。我不这么认为:如果您只运行bash-i
,那么bash将正常启动,并附加了一个tty。在任何情况下,这都不能解释为什么父java进程被挂起。从命令行运行bash-i
与从java代码运行bash-i
不同,因为在shell中已经附加了tty
。不,如果从java作为子进程运行bash-i
,则仍然附加了tty。