循環直到後台程序完成(使用“jobs”)在腳本中不起作用

循環直到後台程序完成(使用“jobs”)在腳本中不起作用

我試圖循環直到後台進程(在腳本的前面啟動)完成。一個易於重現的測試案例是:

ping -c 10 localhost &>/dev/null &

在命令列上,我可以循環while [[ -n $(jobs) ]](while$(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

更令人困惑的是為什麼jobs在循環內運行會使其正常工作。答案與在單獨的子 shell 中while [[ -n $(jobs) ]]運行這一事實有關,jobs但我不確定細節。我有發布了一個問題如果有人有興趣的話,可以在 U&L 上了解這一點。

答案3

您可以使用wait等待後台作業停止的命令

例子:

$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+  Done ping -c 10 localhost &>/dev/null

wait 指令阻塞,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

相關內容