web-dev-qa-db-ja.com

複数のプロセスを実行し、それらのいずれかが終了または失敗した場合に終了する方法

私は複数のプロセスを実行していて、それらのいずれかが失敗または存在する場合、適切な終了コード(これは失敗時のエラー、それ以外の場合は成功を意味します)で終了します。

さらに、子プロセスが終了または失敗した場合は、他の子プロセスもシャットダウンする必要があります。

私の現在の非機能的なソリューション(糸は単なる例です。他のコマンドでもかまいません):

#!/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並列を使用できません。

5
Olivenbaum

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
2
Ole Tange

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 …に置き換えます。