Bash

等待任何程序在 bash 腳本中完成

  • July 1, 2021

我正在嘗試檢查 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是更好的選擇。

引用自:https://unix.stackexchange.com/questions/656103