SIGINTを受け取った後もこのスクリプトが実行され続けるのはなぜですか?

SIGINTを受け取った後もこのスクリプトが実行され続けるのはなぜですか?

私はそれから学んだhttps://unix.stackexchange.com/a/230568/674SIGINTを受信したときにゼロで終了すると、pingそのコマンドを含むbashスクリプトがping終了するのではなく実行できます。

同様の動作をするスクリプトがあります。

#!/bin/bash                                                                                                                                                                       

while true; do
    sudo -S sleep 4;
    echo $?
    sudo -k;
done

実行時にパスワードの入力を求められたら、Ctrl-C と入力するとスクリプトは終了せずに実行を続けます。唯一の違いは、sudoSIGINTを受け取った後、0ではなく1で終了することです。もしそうなら、bashスクリプトが終了せずに実行され続けるのはなぜですか?ありがとうございます。

$ ./test.sh 
[sudo] password for t: 
1
[sudo] password for t: 
1
[sudo] password for t: 
1
...

答え1

このテストは単なる「コマンドが成功したか」テストではありません。プロセスが SIGINT で終了すると、終了状態は次に読み出すことができます。wait(2)WIFSIGNALEDandを使用すると、WTERMSIGbashは子プロセス(この場合はsudo)がシグナルによって直接終了したかどうかを確認できます。

Ctrl + Cを押したときのシステムコールの結果は次のとおりですcat(に従ってstrace)。

wait4(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGINT}], 0, NULL) = 9357

以下でCtrl + Cを押したときの結果ですsudo -S sleep 4

wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 1}], 0, NULL) = 9479

完全性のために、Ctrl + C'ingの結果は次のとおりですping localhost

wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 9710

答え2

明らかに、コマンドはINT信号を処理し、たとえばsudo終了するようにします。sleepしたがって、BashはSIGNITのデフォルトハンドラで自分自身を終了する必要はないと思います。

bashは、SIGINT / SIGQUITパスを処理するときにスタンバイとコラボレーションを終了する方法を実装する数少ないシェルの1つです。スクリプトが解釈されると、SIGINTを受信するとすぐには終了しませんが、現在実行中のコマンドが返されるのを待ち、そのコマンドもそのSIGINTによって終了した場合にのみ終了します(SIGINTで自己終了)。たとえば、スクリプトが vi を呼び出して vi で Ctrl+C を押して操作をキャンセルする場合、これはスクリプトの中断要求とは見なされません。

SIGINTトラップを定義してこの動作をオーバーライドできます。

trap 'trap - INT; kill -s INT $$' INT

引用:https://mywiki.wooledge.org/SignalTrap(4章と5章)

関連情報