私はそれから学んだ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 と入力するとスクリプトは終了せずに実行を続けます。唯一の違いは、sudo
SIGINTを受け取った後、0ではなく1で終了することです。もしそうなら、bashスクリプトが終了せずに実行され続けるのはなぜですか?ありがとうございます。
$ ./test.sh
[sudo] password for t:
1
[sudo] password for t:
1
[sudo] password for t:
1
...
答え1
このテストは単なる「コマンドが成功したか」テストではありません。プロセスが SIGINT で終了すると、終了状態は次に読み出すことができます。wait(2)
。WIFSIGNALED
andを使用すると、WTERMSIG
bashは子プロセス(この場合は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章)