8

別のプログラムを監視する Bourne シェル (/bin/sh) スクリプト (移植性のため) があります。他のプログラムを開始し、それが終了するのを待ちます。2 番目のプログラムが終了すると、最終的な作業を行って終了します。問題は、スクリプトがシグナル (USR2 など) にも応答し、それらのシグナルが表示されたときに何らかの処理を行う必要があることです。

私の素朴な実装は次のとおりです。

#! /bin/sh
echo $$
trap 'echo Respond to USR2' USR2
/bin/sleep 120 &
pid=$!
wait $pid
echo $pid exited with $?
echo Doing final cleanup

これはうまくいきません。シェル SIGUSR2 を送信すると、トラップは期待どおりに起動しますが、wait も終了し、140 が返されます。/bin/sleep は順調に進んでいます。典型的な出力:

28849
Respond to USR2
28850 exited with 140
Doing final cleanup

この動作は、私が便利にアクセスできる 2 つの Bourne シェルの派生物である、dash と bash の間で一貫しています。

私の現在の回避策は、kill でプローブして、子 PID が消えるのを待ってループをスピンすることです。スピン ループは無駄に思えます。また、PID が急速に再利用されている場合、スクリプトが誤って間違ったプロセスを待機している可能性があるウィンドウが拡大します。

#! /bin/sh
echo $$
trap 'echo Respond to USR2' USR2
/bin/sleep 15 &
pid=$!
while /bin/kill -0 $pid 2> /dev/null; do
    echo waiting...
    sleep 2
done
echo Doing final cleanup

別のプロセスが終了するのを同時に待機し、シグナルに応答できるようにするという私の目標を考えると、より良い解決策はありますか?

4

1 に答える 1

3

あなたがすることができます:

while wait $pid; test $? -gt 128; do
    kill -0 $pid 2> /dev/null || break;
done

ただし、sh 標準から次の点に注意してください。

wait の終了ステータスが 128 より大きい場合、待機中のプロセスがその値で終了したのか、シグナルによって強制終了されたのかをアプリケーションが知る方法はありません。ほとんどのユーティリティは小さな値で終了するため、あいまいさはほとんどありません。あいまいなケースであっても、ほとんどのアプリケーションは、非同期ジョブが失敗したことを知る必要があるだけです。エラーを検出して失敗したか、強制終了されてジョブを正常に完了できなかったかに関係ありません。

この場合、あいまいさはわずかに異なります。wait がシグナルによって中断されたのか、それとも子がシグナルによって終了されたのかはわかりません。

于 2012-07-22T13:41:55.630 に答える