複数のプロセスを実行していて、いずれかのプロセスが失敗した場合、または存在する場合(失敗した場合はエラー、そうでなければ成功)、適切な終了コードで終了したいと思います。
また、子プロセスが終了または失敗した場合は、他の子プロセスも終了する必要があります。
現在動作していない解決策(実は単なる例であり、他のコマンドかもしれません):
#!/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プロセスを終了すると、プロセスは引き続き実行されます。cyarn task
yarn schedule
サブプロセスが何であれ(bash、Yarn、PHP、または他のプロセス)、どのように機能させることができますか?
GNU 並列性は使用できません。
答え1
wait
組み込み関数は「何も待たず」ではなく「すべて待つ」ので、シェルではこれが痛いです。wait
パラメータがない場合は、すべての子プロセスが終了するのを待って0を返します。wait
明示的なプロセスリストを使用している場合は、すべての子プロセスが終了するのを待ち、最後の引数の状態を返します。複数の子供を待って子供の終了ステータスを確認するには、別のアプローチを取る必要があります。wait
これは、どの子供が死亡したかを知っている場合にのみ終了ステータスを提供します。
1つの可能なアプローチは、専用の名前付きパイプを使用して各子孫の状態を報告することです。次のコードスニペット(テストされていません!)は、最大のサブステータスを返します。
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つが状態を報告せずに死ぬと、永遠にブロックされます。これは通常の状況では発生しませんが、サブシェルが手動で終了した場合、またはサブシェルにメモリが不足している場合に発生する可能性があります。
子のいずれかが失敗したときにすぐに特定のタスクを実行するには、if [ $status -gt $max_status ]; then …
に置き換えますif [ $status -ne 0 ]; then …
。
答え2
GNU パラレルでは、いずれ--halt
かのジョブが完了または終了すると実行中のすべてのジョブが終了し、ジョブが失敗した場合は 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 がインストールされていないシステムでは、通常、次の場所にスクリプトを作成できます。持つGNU Parallel、--embed
GNU Parallelをスクリプトに直接含めるために使用されます。
parallel --embed > myscript.sh