Capturing SIGINT using KeyboardInterrupt exception works in terminal, not in script
我试图在Python 2.7程序中捕获
1 2 3 4 5 6 7 8 9 10 | #!/usr/bin/python import time try: time.sleep(100) except KeyboardInterrupt: pass except: print"error" |
接下来我有一个shell脚本
1 2 3 | ./test & pid=$! sleep 1 kill -s 2 $pid |
当我使用bash,或sh或
我不知道发生了什么,我想了解。 那么,差异在哪里,为什么?
这不是关于如何在Python中捕获
Python installs a small number of signal handlers by default: SIGPIPE ... and SIGINT is translated into a KeyboardInterrupt exception
如果程序是直接从shell启动的话,当
有一种情况是在启动时未安装默认的sigint处理程序,即在程序启动时信号掩码包含
忽略信号的信号掩码从父进程继承,而处理信号则重置为
因此,让我们尝试在不同的情况下显示使用过的信号处理程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # 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 |
所以在最后一个例子中,
所以这是由shell在非交互式shell会话中启动后台作业时忽略信号引起的,而不是直接由python引起的。至少
有两种方法可以解决这种情况:
-
手动安装默认信号处理程序:
1
2import signal
signal.signal(signal.SIGINT, signal.default_int_handler) -
将
-i 选项添加到shell脚本的shebang中,例如:1#!/bin/sh -i
编辑:bash手册中记录了此行为:
SIGNALS
...
When job control is not in effect, asynchronous commands ignore SIGINT and SIGQUIT in addition to these inherited handlers.
它适用于非交互式shell,因为它们默认禁用了作业控制,实际上是在POSIX:Shell Command Language中指定的