Bash
等待任何程序在 bash 腳本中完成
我正在嘗試檢查 bash 腳本中正在執行多少活動程序。這個想法是讓 x 個程序保持執行,當一個程序完成時,下一個程序就會啟動。
出於測試目的,我設置了這個腳本:
find $HOME/Downloads -name "dummy" & find $HOME/Downloads -name "dummy" & find $HOME/Downloads -name "dummy" & while true do pids=() while read pid; do echo "PID: $pid" pids+=("$pid") done < <(jobs -p) jobs -p echo "Active processes: ${#pids[@]}" if [ ${#pids[@]} -lt 2 ]; then break fi echo "Process(es) still running... ${pids[@]}" sleep 1 done
但這不起作用,因為
jobs -p
即使程序完成,也會繼續返回作業 ID。以下範例詳細說明了該問題:
#!/bin/bash find $HOME/Downloads -name "dummy" & find $HOME/Downloads -name "dummy" & find $HOME/Downloads -name "dummy" & while true do jobs -p # continues to print all 3 jobs sleep 1 done
如何獲得
while
循環中的活動作業?問候,
腳本的問題是其中沒有任何內容會呼叫等待系統呼叫之一。通常,在呼叫 wait 之前,核心會為該程序保留一個條目,因為這是儲存子程序的返回碼的地方。如果父程序在子程序之前結束,則子程序重新成為父程序,通常為 PID 1。一旦系統啟動,PID 1 通常被程式為進入一個循環,只需呼叫等待來收集這些程序的退出值。
重寫測試腳本呼叫
wait
我們得到的shell內置函式pids=() find $HOME/Downloads -name "dummy" & pids+=( $! ) find $HOME/Downloads -name "dummy" & pids+=( $! ) find $HOME/Downloads -name "dummy" & pids+=( $! ) echo "Initial active processes: ${#pids[@]}" for ((i=${#pids[@]}; i>1; i--)) ; do do wait -n # Wait for one process to exit echo "A process exited with RC=$?" # Note that -n is a bash extension, not in POSIX # if we have bash 5.1 then we can use "wait -np EX" to find which # job has finished, the value is put in $EX. Then we can remove the # value from the pids array. echo "Still outstanding $(jobs -p)" sleep 1 done
雖然
wait -n
(根據@icarus 的評論)在這種特殊情況下有效,但應注意它$!
包含最後啟動的程序的 PID。因此,您也可以對此進行測試:#!/bin/bash find $HOME/Downloads -name "dummy" & p1=$! find $HOME/Downloads -name "dummy" & p2=$! find $HOME/Downloads -name "dummy" & p3=$! while true do if ps $p1 > /dev/null ; then echo -n "p1 runs " else echo -n "p1 ended" fi if ps $p2 > /dev/null ; then echo -n "p2 runs " else echo -n "p2 ended" fi if ps $p1 > /dev/null ; then echo -n "p3 runs " else echo -n "p3 ended" fi echo '' sleep 1 done
但是
parallel
是更好的選擇。