他の信号を乱さずに信号をキャプチャ

他の信号を乱さずに信号をキャプチャ

シェルスクリプトから信号をキャプチャすると、キャプチャコマンドは現在のコマンドが完了するまで実行されません。たとえば、次のシェルスクリプトを考えます。

#!/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

他の信号の不適切な処理を防ぐために、トラップにどのような変更が必要ですか?

ベストアンサー1

おすすめ記事