加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

使用KeyboardInterrupt异常捕获SIGINT在终端中工作,而不是在脚本

发布时间:2020-12-15 19:00:23 所属栏目:安全 来源:网络整理
导读:我试图在Python 2.7程序中捕获SIGINT(或键盘中断).这是我的Python测试脚本测试的外观: #!/usr/bin/pythonimport timetry: time.sleep(100)except KeyboardInterrupt: passexcept: print "error" 接下来我有一个shell脚本test.sh: ./test pid=$!sleep 1kill
我试图在Python 2.7程序中捕获SIGINT(或键盘中断).这是我的Python测试脚本测试的外观:
#!/usr/bin/python

import time

try:
    time.sleep(100)
except KeyboardInterrupt:
    pass
except:
    print "error"

接下来我有一个shell脚本test.sh:

./test & pid=$!
sleep 1
kill -s 2 $pid

当我使用bash或sh或者bash test.sh运行脚本时,Python进程测试保持运行并且不能使用SIGINT运行.而当我复制test.sh命令并将其粘贴到(bash)终端时,Python进程测试将关闭.

我不知道发生了什么,我想了解.那么,差异在哪里,为什么?

这不是关于如何在Python中捕获SIGINT!根据docs – 这是应该工作的方式:

Python installs a small number of signal handlers by default: SIGPIPE … and SIGINT is translated into a KeyboardInterrupt exception

如果程序是直接从shell启动的话,当kill发送SIGINT时确实捕获KeyboardInterrupt,但是当从后台运行的bash脚本启动程序时,似乎从不引发KeyboardInterrupt.

有一种情况是在启动时未安装默认的sigint处理程序,即在程序启动时信号掩码包含SIGINT的SIG_IGN.负责此操作的代码可以在 here找到.

忽略信号的信号掩码从父进程继承,而处理信号则重置为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).这与在shell脚本中启动后台作业时相同,因为默认情况下它们是非交互式的(除非在shebang中使用-i选项).

所以这是由shell在非交互式shell会话中启动后台作业时忽略信号引起的,而不是直接由python引起的.至少bash和dash表现得这样,我没有尝试过其他的shell.

有两种方法可以解决这种情况:

>手动安装默认信号处理程序:

import signal
signal.signal(signal.SIGINT,signal.default_int_handler)

>将-i选项添加到shell脚本的shebang中,例如:

#!/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中指定的

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读