sleep
手動で実行すると、kill -INT
スリープはすぐに終了します。例:
$ /bin/sleep 60 &
[1] 4002356
$ kill -INT 4002356
[1]+ Interrupt /bin/sleep 60
$ ps -C sleep
PID TTY TIME CMD
$
ただし、シェル スクリプトで同じことを実行すると、sleep
は無視されますSIGINT
。例:
set -o xtrace
echo
/bin/sleep 10 &
child="$!"
/bin/sleep 0.1
ps -C sleep
kill -TERM "$child" # SIGTERM
/bin/sleep 0.1
ps -C sleep
wait "$child" # will return immediately
echo
/bin/sleep 10 &
child="$!"
/bin/sleep 0.1
ps -C sleep
kill -INT "$child" # SIGINT
/bin/sleep 0.1
ps -C sleep
wait "$child" # will wait for 9.8 seconds
シェル スクリプト内でSIGINT
実行する場合、sleep はなぜ/どのように無視されるのですか?sleep
dash
とでも同じ動作になりますbash
。カーネルは Linux 5.4.0 です。
答え1
/bin/sleep 10 &
終了すると、&
シェルはsleep
非同期で実行されます。スクリプトでは、ジョブ制御はデフォルトで無効になっています。Bash では、次のようになります [強調は筆者による]。
Bash によって開始された非組み込みコマンドには、シェルが親から継承した値に設定されたシグナル ハンドラーがあります。ジョブ制御が有効でない場合、非同期コマンドはSIGINTを無視します。これらの継承されたハンドラに加えて、SIGQUIT も追加されます。
ソース:Bash リファレンスマニュアル。
同様に、SIG_IGN
は の呼び出し後も存続しますexecv()
が、 は例外となる可能性がありますSIGCHLD
。
呼び出しプロセス イメージでデフォルト アクション (SIG_DFL) に設定されたシグナルは、新しいプロセス イメージでもデフォルト アクションに設定されます。SIGCHLD を除き、呼び出しプロセス イメージによって無視されるように設定されたシグナル (SIG_IGN) は、新しいプロセス イメージによって無視されるように設定されます。呼び出しプロセス イメージによってキャッチされるように設定されたシグナルは、新しいプロセス イメージでデフォルト アクションに設定されます (<signal.h> を参照)。