Python 2.7プログラムでSIGINT
(またはキーボード割り込み)をキャッチしようとしています。これが私のPythonテストスクリプトtest
ルックス:
#!/usr/bin/python
import time
try:
time.sleep(100)
except KeyboardInterrupt:
pass
except:
print "error"
次に、シェルスクリプトtest.sh
があります:
./test & pid=$!
sleep 1
kill -s 2 $pid
Bash、sh、またはbash test.sh
を使用してスクリプトを実行すると、Pythonプロセスtest
は実行されたままになり、SIGINT
で強制終了できません。 。一方、test.sh
コマンドをコピーして(bash)ターミナルに貼り付けると、Pythonプロセスtest
がシャットダウンします。
何が起こっているのかわからないので、理解したい。では、違いはどこにあり、なぜですか?
これは、PythonでSIGINT
をキャッチする方法ではありません!docs によると、これが方法です。動作するはずです:
Pythonはデフォルトで少数のシグナルハンドラーをインストールします:SIGPIPE ...そしてSIGINTはKeyboardInterrupt例外に変換されます
プログラムがシェルから直接開始された場合、KeyboardInterrupt
がSIGINT
によって送信されたときに、実際にkill
をキャッチしていますが、プログラムがバックグラウンドで実行されたbashスクリプトから開始された場合、そのKeyboardInterrupt
は決して発生しません。
デフォルトのsigintハンドラーが起動時にnotインストールされていない場合があります。それは、シグナルマスクにSIGINT
の_SIG_IGN
_が含まれている場合です。プログラムの起動。これを担当するコードは ここ にあります。
無視されたシグナルのシグナルマスクは親プロセスから継承され、処理されたシグナルは_SIG_DFL
_にリセットされます。したがって、SIGINT
が無視された場合、ソースの条件if (Handlers[SIGINT].func == DefaultHandler)
はトリガーされず、デフォルトハンドラーがインストールされません。pythonは、親によって行われた設定をオーバーライドしません。この場合のプロセス。
それでは、さまざまな状況で使用されるシグナルハンドラーを表示してみましょう。
_# invocation from interactive Shell
$ python -c "import signal; print(signal.getsignal(signal.SIGINT))"
<built-in function default_int_handler>
# background job in interactive Shell
$ python -c "import signal; print(signal.getsignal(signal.SIGINT))" &
<built-in function default_int_handler>
# invocation in non interactive Shell
$ sh -c 'python -c "import signal; print(signal.getsignal(signal.SIGINT))"'
<built-in function default_int_handler>
# background job in non-interactive Shell
$ sh -c 'python -c "import signal; print(signal.getsignal(signal.SIGINT))" &'
1
_
したがって、最後の例では、SIGINT
は1(_SIG_IGN
_)に設定されています。これは、シェルスクリプトでバックグラウンドジョブを開始する場合と同じです。これらはデフォルトで非対話型であるためです(Shebangで_-i
_オプションを使用する場合を除く)。
したがって、これは、非対話型シェルセッションでバックグラウンドジョブを起動するときにシェルがシグナルを無視するためであり、python直接ではありません。少なくともbash
とdash
はこのように動作しますが、試していません。他のシェル。
この状況に対処するには、次の2つのオプションがあります。
デフォルトのシグナルハンドラを手動でインストールします。
_import signal
signal.signal(signal.SIGINT, signal.default_int_handler)
_
_-i
_オプションをシェルスクリプトのシバンに追加します。例:
_#!/bin/sh -i
_
編集:この動作はbashマニュアルに記載されています:
信号
.。
ジョブ制御が有効になっていない場合、非同期コマンドは、これらの継承されたハンドラーに加えて、SIGINTとSIGQUITを無視します。
これは、デフォルトでジョブ制御が無効になっている非対話型シェルに適用され、実際にはPOSIXで指定されています。 シェルコマンド言語