bash はシグナルによる子プロセスの異常終了時に終了しません

bash はシグナルによる子プロセスの異常終了時に終了しません

自分が何を間違っているのか、そしてなぜ間違っているのかを理解しようと一生懸命努力しています。

launch.shを起動するスクリプトがありますprocess.sh

起動.sh

#!/bin/bash
while true; do 
./process.sh 
done

プロセス.sh

#!/bin/bash
function signalHandler() {
    for i in {1..2}; do
        sleep 0.1s
        echo "process.sh: cleanup $i"
    done
    exit 130
}

trap "signalHandler" "SIGINT"

while true; do 
sleep 1s
done

走るとき

./launch.sh &

そしてそれを殺す

kill -s SIGINT -$!    

ここで、$!最後のコマンド (launch.sh) の PID を取得し、マイナス記号ですべての子に信号を送信してからlaunch.sh続行します。なぜでしょうか?


私は次のような動作を期待していました(このブログによるとシグナルとバッシュ) :

バックグラウンドでスクリプトを実行しているシェル Alaunch.shが中断され、Bash はprocess.shが終了するまで待機します。process.shのシグナル ハンドラにより が異常終了 (終了 130) を返すためprocess.sh、シェル A は終了するはずです。なぜ終了しないのでしょうか。

この子のステータスが、そのシグナルが原因で異常終了したことを示している場合、シェルはクリーンアップし、シグナル ハンドラーを削除し、OS のデフォルト アクション (異常終了) をトリガーするために再度自身を強制終了します。または、trap で設定されたスクリプトのシグナル ハンドラーを実行して、続行します。

答え1

まず、exit 130これは異常終了ではありません。これは正常終了であり、終了ステータスは130です。man 3 wait(POSIX):

   If  the  information  pointed  to  by  stat_loc was stored by a call to
   waitpid()  that  specified  the  WUNTRACED     and  WCONTINUED   flags,
   exactly one of the macros WIFEXITED(*stat_loc), WIFSIGNALED(*stat_loc),
   WIFSTOPPED(*stat_loc),  and WIFCONTINUED(*stat_loc)  shall evaluate  to
   a non-zero value.

WIFEXITEDは正常終了をチェックし、 はWIFSIGNALLEDキャッチされないシグナルによる終了です。これらは相互に排他的であるため、 はexit 130正常です。

プロセスが SIGINT によって終了したときに終了ステータスが 130 になるのは、bash が SIGINT による終了を検出したため、プロセス外で終了ステータスを 130 に設定するためです。bash が Ctrl-C または Ctrl-Z で $? (終了ステータス) をゼロ以外に設定するのはなぜですか?

第二に、SIGINTを処理して終了するプロセスは、SIGINTで自分自身を終了させる必要があります。Gregのwiki(シェル関連の優れたリソース)には、これについてのメモ:

SIGINTのハンドラを設定する場合(EXITトラップを使用するのではなく)、SIGINTに応答して終了するプロセスはSIGINTで自分自身を殺す呼び出し元に問題が起こらないように、単に終了するのではなく、次のようになります。

trap 'rm -f "$tempfile"; trap - INT; kill -INT $$' INT

ここで、をexit 130次のように変更したとします。

trap - INT
kill -INT $$

予想通りの動作が見られます。

関連情報