シェルスクリプトから信号をキャプチャすると、キャプチャコマンドは現在のコマンドが完了するまで実行されません。たとえば、次のシェルスクリプトを考えます。
#!/bin/bash
trap 'echo "SIGTERM caught"' SIGTERM
i=0
while : ; do
echo "$((++i))"
timeout 10 yes >/dev/null
done
このスクリプトを実行してSIGTERMをプロセスに送信しようとすると、アクティブなコマンドが完了するまでトラップ関数のechoステートメントは実行されません。
コマンドをバックグラウンドに配置し、スタンバイを使用してコマンドの実行中に信号を処理できます。たとえば、次のようになります。
#!/bin/bash
trap 'echo "SIGTERM caught"; [[ "$pid" ]] && echo "Killing $pid" && kill "$pid"' SIGTERM
i=0
while : ; do
echo "$((++i))"
timeout 10 yes >/dev/null &
pid=$!
wait
done
ただし、SIGTERMがすぐに見つかった場合でも、プロセスは他のシグナル(SIGINTなど)に誤って応答します。たとえば、上記のスクリプトを実行してもSIGTERMが数分前に送信された場合、SIGINTでスクリプトを終了することはできません。たとえば、$pid
シェルスクリプトのプロセスIDの場合、次のいずれかがプロセスを終了します(後者の場合、プロセスはSIGTERMに応答する前にSIGINTによって中断されます)。
kill -SIGINT "$pid"
kill "$pid"; kill -SIGINT "$pid"
これはそうではありません(プロセスは停止し、SIGKILLを渡して終了する必要があります)。
kill "$pid"; sleep 0.01; kill -SIGINT "$pid"
SIGTERM caught
# process hangs at this point
他の信号の不適切な処理を防ぐために、トラップにどのような変更が必要ですか?