如何在java中调用ProcessBuilder运行nohup...&格式的bash命令?
我现在有一个简单的bash脚本t.sh。这个脚本维护一个计数器,每过1s,该计数器会+1,并且将当前该计数器的值输出到标准输出上。
#!/bin/bash
counter=0
while true; do
counter=$((counter + 1))
echo $counter
sleep 1
done
我可以直接使用nohup bash t.sh &
来在linux环境下运行该脚本,该脚本会在nohup.out中输出下面的预期结果
1
2
3
......
现在,我想要在Java中通过ProcessBuilder来运行该脚本。我可以使用下列方法
@Test
void testNohupInOne() throws IOException, InterruptedException {
// String cmd = "nohup bash t.sh &";
String cmd = "bash t.sh";
String[] cmds = new String[] { "bash", "-c", cmd };
ProcessBuilder processBuilder = new ProcessBuilder(cmds);
Process process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
reader.lines().forEach(line -> {
System.out.println(line);
});
}
process.waitFor();
}
上述方法可以正常在java程序的标准输出上,输出和直接在linux终端中使用nohup bash t.sh &
后在nohup.out中一样的结果。
然而,如果我们将java中使用的命令替换为bash t.sh
,即将上面testNohupInOne方法的第一行取消注释,而第二行添加注释
String cmd = "nohup bash t.sh &";
// String cmd = "bash t.sh";
那么,java程序只会输出1
。
1
这似乎意味着,java程序会立刻结束nohup...&
格式的命令的运行,而非如同预期一般将其作为后台进程持续运行。
如果我们将bash脚本中counter的初始值从0改为3,则java程序的输出会对应的变为仅有4
一行。
我想要知道,为什么java程序会产生这样的行为?如果我想要在java程序中通过ProcessBuilder运行nohup...&
格式的bash命令,是否有比较优雅的实现方式?
机器人回答的可靠,我建议你通过
Runtime.getRuntime().exec():
,另外把脚本改一下因为你使用
echo
输出,这是在标准输出的,nohup
会创建一个nohup.out
文件接收你的输出,&
将任务丢在了后台,你通过ProcessBuilder
的流读取结果时,任务已经在后台运行了。你可以先启动程序,然后去监听
/tmp/res.dat
的变化,这样结果就是准确的