シェル スクリプトで sleep を実行すると、SIGINT が無視されるのはなぜですか?

シェル スクリプトで sleep を実行すると、SIGINT が無視されるのはなぜですか?

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> を参照)。

ソース:オープングループ基本仕様第7号、2018年版

関連情報