web-dev-qa-db-ja.com

SIGINTまたはSIGTERMが子プロセスではなく親スクリプト自体に送信されるときにコマンドまたは関数を実行する

これを持っているとしましょうscript.sh

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

echo "Some other text"
#other commands here
sleep infinity

が欲しいです script.sh関数を実行するにはexit_scriptSIGINTまたはSIGTERMを受け取ったときはいつでも

killall script.sh # it will send SIGTERM to my script

スクリプトでこれを実行したい

exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trapを使用してこの機能を実装しようとしました

trap exit_script SIGINT SIGTERM

私の質問に答えた人が私を誤解した。
しかし、trapは子/サブプロセスに送信されたシグナルにのみ反応するように見えるため、機能しませんでした。初心者としてtrapのmanページを解読できなかったので、おそらく解決策を見逃しました。

これは、Chromiumのような「実際の」プログラムが送信するときにSIGTERMが行うことだと思います。

From https://major.io/2010/03/18/sigterm-vs-sigkill/ から

アプリケーションは、SIGTERMを受信すると何をしたいかを決定できます。ほとんどのアプリケーションはリソースをクリーンアップして停止しますが、そうでないアプリケーションもあります。

11
bosa djo

trapは、呼び出しプロセスのシグナル自体に反応します。ただし、信号を受信する前に呼び出す必要があります。つまり、スクリプトの冒頭です。

さらに、スクリプトにも信号を送信するkill -- -$$を使用する場合は、killを実行する前にトラップをクリアする必要があります。そうしないと、無限kill && trapループで終了します。

例えば:

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    trap - SIGINT SIGTERM # clear the trap
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trap exit_script SIGINT SIGTERM

echo "Some other text"
#other commands here
sleep infinity

コメントで説明されているように、問題はスクリプトが信号を受信するが、受信した信号を処理する前にスリーププログラムが終了するのを待っていることです。したがって、トラップアクションを実行するには、子プロセス(この場合はスリーププロセス)を強制終了する必要があります。次のような方法でそれを行うことができます:

kill -- -$(pgrep script.sh)

またはコメントで述べたように:

killall -g script.sh
15
zuazo