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