私は複数のプロセスを実行していて、それらのいずれかが失敗または存在する場合、適切な終了コード(これは失敗時のエラー、それ以外の場合は成功を意味します)で終了します。
さらに、子プロセスが終了または失敗した場合は、他の子プロセスもシャットダウンする必要があります。
私の現在の非機能的なソリューション(糸は単なる例です。他のコマンドでもかまいません):
#!/bin/bash -e
# Run other process before start
sh ./bin/optimize.sh
trap 'exit' INT TERM
trap 'kill -INT 0' EXIT
# Run Schedule
sh ./bin/schedule.sh &
# Run a long running task
yarn task &
wait
./bin/schedule.sh
:
#!/bin/bash -e
while true; do
yarn schedule
sleep 30
done
何かがyarn schedule
は失敗し、すべてが正しく存在します。しかし、私がプロセスを殺すとき ctrl+c またはyarn task
終了yarn schedule
は実行し続けます。
子プロセスが何であるかに関係なくこれを機能させる方法(bash、yarn、phpなど)?
GNU並列を使用できません。
GNU Parallelには--halt
。ジョブの1つが終了または終了した場合、実行中のすべてのジョブを強制終了し、ジョブが失敗した場合はfalseを返します。
parallel --halt now,done=1 ::: 'sleep 1;echo a' 'sleep 2;echo b' ||
echo the job that finished failed
parallel --halt now,done=1 ::: 'sleep 1;echo a;false' 'sleep 2;echo b' ||
echo the job that finished failed
GNU Parallelがインストールされていないシステムの場合、通常はhas GNU Parallel、使用する --embed
を埋め込むGNUスクリプトに直接並列:
parallel --embed > myscript.sh
wait
組み込み関数は「すべてを待つ」のではなく、「すべてを待つ」ので、これはシェルでは苦痛です。引数なしのwait
は、すべての子が終了するまで待機し、0を返します。プロセスの明示的なリストを持つwait
は、すべての子が終了するまで待機し、最後の引数のステータスを返します。複数の子を待って終了ステータスを取得するには、別のアプローチが必要です。 wait
は、どの子がすでに死んでいるかがわかっている場合にのみ、終了ステータスを提供できます。
可能なアプローチの1つは、専用の名前付きパイプを使用して、各子のステータスを報告することです。次のスニペット(unested!)は、子供のステータスの最大値を返します。
mkfifo status_pipe
children=0
{ child1; echo 1 $? >status_pipe; } & children=$((children+1))
{ child2; echo 2 $? >status_pipe; } & children=$((children+1))
max_status=0
while [ $children -ne 0 ]; do
read -r child status <status_pipe
children=$((children-1))
if [ $status -gt $max_status ]; then
max_status=$status
fi
done
rm status_pipe
サブシェルの1つがそのステータスを報告せずに死んだ場合、これは永久にブロックすることに注意してください。これは通常の状況では発生しませんが、サブシェルが手動で強制終了された場合、またはサブシェルがメモリ不足になった場合に発生する可能性があります。
子の1つが失敗した直後に何かを実行したい場合は、if [ $status -gt $max_status ]; then …
をif [ $status -ne 0 ]; then …
に置き換えます。