Bashスクリプトのプロセスが完了するのを待ちます。

Bashスクリプトのプロセスが完了するのを待ちます。

Bashスクリプトで実行されているアクティブなプロセスの数を確認しようとしています。アイデアは、xプロセスを実行し続け、1つのプロセスが完了すると、次のプロセスが開始されることです。

テスト目的で次のスクリプトを設定しました。

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ループでアクティブなタスクを取得するには?

挨拶、

答え1

(@icarusのコメントに従って)この特別なケースでは機能しますが、最後に開始されたプロセスのPIDが含まれているwait -nことに注意してください。$!したがって、これをテストすることもできます。

#!/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それもより良い選択です。

答え2

このスクリプトの問題は、その中にあるものがスタンバイシステムコールの1つを呼び出さないことです。通常、カーネルは待機を呼び出す前にプロセスのエントリを予約します。なぜなら、ここに子プロセスの戻りコードが格納されているからです。親プロセスが子プロセスの前に終了すると、子プロセスは通常、PID 1 で親プロセスをリセットします。システムが起動した後、PID 1は通常ループに入り、待機のみを呼び出してこれらのプロセスの終了値を収集するようにプログラムされます。

wait私たちが得たシェル組み込み関数を呼び出すようにテストスクリプトを書き直します。

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

答え3

Bashスクリプトで実行されているアクティブなプロセスの数を確認しようとしています。アイデアは、xプロセスを実行し続け、1つのプロセスが完了すると、次のプロセスが開始されることです。

GNU Parallelを使用すると、次のようになります。

parallel -j3 find $HOME/Downloads -name {} ::: "name1" "name2" "name3"

(他のパラメータだけでなく)他のプログラムを実行する必要がある場合:

parallel -j3 ::: "find $HOME/Downloads -name name1" "find $HOME/Downloads -name name2"  "find $HOME/Downloads -name name3" 

コマンドがより複雑な場合は、bash機能を使用してください。

find1() {
  find $HOME/Downloads -name "name1"
}
find2() {
  find $HOME/Downloads -name "name2"
}
find3() {
  find $HOME/Downloads -name "name3"
}
export -f find1 find2 find3
parallel -j3 ::: find1 find2 find3

省略すると、-j3CPUコアごとに1つのジョブが実行されます。

関連情報