我尝试循环执行,直到后台进程(在脚本中较早启动)完成。一个易于重现的测试用例是:
ping -c 10 localhost &>/dev/null &
在命令行上,我可以循环while [[ -n $(jobs) ]]
(当$(jobs)
不为空时)。
$ ping -c 10 localhost &>/dev/null &
[1] 19078
$ while [[ -n $(jobs) ]]; do echo -n .; sleep 1; done
.........[1]+ Done ping -c 5 localhost &> /dev/null
但是,脚本中的相同两行将继续打印.
s 直到我点击Ctrl-C
。
奇怪的是,如果我jobs
在循环内调用,脚本就会按预期结束。
$ ./background-ping.sh
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Done ping -c 5 localhost &> /dev/null
我知道还有其他方法可以检查后台作业是否完成(例如检查/proc
),但我想知道为什么检查jobs
不能按预期进行。
答案1
如果我理解了你的问题,你的两行代码就不会在脚本中停止。
这就是我做的:
ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done
jobs -r
检查正在运行的进程,并且调用我的脚本按预期工作,当 ping 完成时脚本停止。
编辑:我认为在脚本中,父进程被称为正在运行的进程,这就是为什么jobs
继续认为有一个正在运行的进程。这是一个假设
这就是答案吗?(或者也许我真的不明白你的意思,我的英语不好可能是问题所在......)
答案2
无论何时遇到此类问题,您都应该尝试打印变量,以便了解发生了什么。在这种情况下,jobs
还会返回已完成的作业。如果您运行此命令:
ping -c 5 localhost &>/dev/null &
while [[ -n $(jobs | tee -a temp) ]]; do
echo -n .;
sleep 1;
done
您将在 中看到以下输出temp
:
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[...]
所以,这里的输出jobs
永远不会为空。即使作业完成,jobs
仍然会返回Done
消息。这就是 Metal3d 的解决方案奏效的原因jobs -r
。
更令人困惑的是为什么在循环内运行会导致它正常工作。答案可能与在单独的子 shell 中运行jobs
有关,但我不确定细节。我有while [[ -n $(jobs) ]]
jobs
发了一个问题如果有人感兴趣的话,可以在 U&L 上查看这个内容。
答案3
您可以使用wait
等待后台作业停止的命令
例子:
$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+ Done ping -c 10 localhost &>/dev/null
等待命令阻塞,当ping
完成时,提示被释放然后打印一条消息。
您可以将 is 与多个命令一起使用:
$ ping -c 5 localhost &>/dev/null & ping -c 5 facebook.com &>/dev/null &
[1] 29867
[2] 29868
$ wait
[1]- Done ping -c 5 localhost &>/dev/null
[2]+ Done ping -c 5 facebook.com &>/dev/null