sudo サブプロセスが終了すると Bash スクリプトを終了する

sudo サブプロセスが終了すると Bash スクリプトを終了する

Bashスクリプトで複数のサブルーチンを起動して待ちます。誰でももう一方を終了し、スクリプトを終了する前にもう一方を終了します。

CMD1PID=
CMD2PID=

出口トラップ(){
    echo "トラップ終了:ジョブ終了..."
    sudo kill $CMD1PID $CMD2PID
    出口
}

セットBM
トラップ終了_トラップ終了INT用語

sudo cmd1 --args &
CMD1PID=$?

sudo cmd2 --args &
CMD2PID=$?

$CMD1PID $CMD2PID を待ちます。

(参考としてGNU bash, version 4.2.37(1)-release (arm-unknown-linux-gnueabi)Debian Weezyにあります)

残念ながら、これは正しく動作しないようです。私は次のようないくつかのバリエーションを試しました。

  • コマンドの周りに中かっこを使用してから、シェルプロセスを明示的に終了します。つまり、{ cmd1 --args ; kill -USR1 $$ ; } &同様のプロセスを終了してUSR1をキャプチャします。
  • kill 0終了時にまだ実行中のコマンドを終了するために使用されます。
  • トラップ - 欠点は、CHLD必要に応じてコマンドを切り替えることができないことです。最終的に切り替える必要があるかもしれません。sleep

...しかし、私がよく直面する問題は次のとおりです。

  • いずれかのコマンドを終了しても、親 Bash プロセスが終了するか、他のコマンドは終了しません。
  • 親 Bash プロセスを終了しても、両方のコマンドは終了しません。

おそらく、他のスクリプトの他のスクリプトが似たようなスクリプトを使って幸運に思われるので、sudoを使用する必要があるという要件が私を妨げているようです。 Bashでやりたいことをするための良い方法はありますか?

答え1

2つの問題があります。興味深い子供たちがいつ終わるかを決定し、すべての子供たちを殺す必要があります。

1つ目は、組み込みの「待機」を使用できないという意味です。みんな子供(またはリスト内のすべての子供)には適していません。どの。 USR1に基づくあなたの提案はEXITだけでなく、それにも適しています。

2番目ははるかに難しいです。 sudoを使用しているため、実際にプロセスにシグナルを送信する権限がなく、ユーザーIDが一致するか、ルートである必要があります。

ファイルシステムやファイルハンドルベースのシグナルなどを試してみることができますが、正直なところ、これは他のスクリプト言語(Python、Perlなど)で理解しやすく、読みやすく、メンテナンスしやすく、複雑すぎるかもしれません。ターゲットユーザーの下でスクリプト全体を実行することをお勧めします。

答え2

UNIXスタイルの「複雑なタスクをより小さなタスクに分割する」ことを提案している場合は、sudoの問題を解決することから始め、より単純な「サブプロセスが終了したときにBashスクリプトを終了する」という問題が残ります。子供の直系の親。

#!/bin/sh

exec sudo sh -c '
  exit_trap() {
     kill # pids
  }
  trap exit_trap SIGNALS
  # run children &
  wait # pids
'

この時点で、スクリプトはデフォルトで一重引用符で囲まれた内部スクリプトを囲むsudoサポートラッパーです。これが価値があるかどうかはわかりませんが、execsudo呼び出し(この場合は削除したい場合)の前後に実行する必要がある追加のコードが原因で、この奇妙な動作が価値がある可能性があります。

関連情報