python SIGINT不终止调用外壳
当从Linux shell(在bash和ksh中观察到同样的行为)运行Python并通过Ctl-C按键生成SIGINT时,我发现了我无法理解的行为,并且这让我非常沮丧。python SIGINT不终止调用外壳
当我按下Ctl-C时,Python进程正常终止,但shell继续执行下一个命令。
$ python -c "import time; time.sleep(100)"; echo END ^CTraceback (most recent call last):
File "<string>", line 1, in <module>
KeyboardInterrupt
END
相比之下,我的预期,并希望,该外壳处理信号以这样的方式,执行不继续下一个命令就行了,因为我看到的时候我所说的睡眠功能从bash子shell而不是从Python。
$ bash -c "sleep 100"; echo END ^C
Python 2和3被安装在我的系统,并同时产生上述捕获运行Python 2中,两个行为相同的方式。
$ python --version Python 2.7.14
$ python3 --version
Python 3.6.3
我最好的解释是,当我按CTL-C,而Python的进程正在运行时,信号以某种方式直接进入Python的过程,而通常它是由主叫壳处理,然后传播到子。但是,我不知道Python为什么或者如何导致这种差异。
上面的例子是简单的测试,但在现实世界的使用中也观察到了这种行为。安装自定义信号处理程序不能解决问题。
回答:
经过相当多的挖掘后,我发现堆栈溢出几个松散相关的问题,最终导致我到article describing the proper handling of SIGINT。 (最相关的部分是如何成为一个合适的程序。)
从这些信息,我能够解决这个问题。没有它,我就永远不会接近。
的解决方案是最好用不能由一个键盘中断终止bash脚本开始说明,但是这确实隐藏Python的KeyboardInterrupt异常丑陋的堆栈跟踪:
#!/usr/bin/env bash echo "Press Ctrl-C to stop... No sorry it won't work."
while true
do
python -c '
import time, signal
signal.signal(signal.SIGINT, signal.SIG_IGN)
time.sleep(100)
'
done
的变化,使外脚本处理中断是:
echo "Press Ctrl-C to stop..." while true
do
python -c '
import time, signal, os
signal.signal(signal.SIGINT, signal.SIG_DFL)
time.sleep(100)
'
done
但是,此解决方案使得不可能使用自定义处理程序(例如,执行清理)。如果要求这样做,则需要更复杂的方法:
#!/usr/bin/env bash echo "Press [CTRL+C] to stop ..."
while true
do
python -c '
import time, sys, signal, os
def handle_int(signum, frame):
# Cleanup code here
signal.signal(signum, signal.SIG_DFL)
os.kill(os.getpid(), signum)
signal.signal(signal.SIGINT, handle_int)
time.sleep(100)
'
done
的原因似乎是,除非内部过程终止通过执行由系统提供的默认SIGINT处理程序,父bash进程没有意识到该孩子因键盘中断而终止,并且本身不终止。
我还没有完全理解所有的辅助问题,比如父进程是不是从系统接收到SIGINT,还是正在接收信号,但忽略它。我也不知道默认处理程序是做什么的,或者父母如何检测它被调用。如果我能够学到更多,我会提供更新。
我必须提出一个问题:Python的当前行为是否应该被认为是Python中的一个设计缺陷。多年来,在从shell脚本中调用Python的过程中,我已经看到了这个问题的各种表现,但直到现在还没有调查过。但是,我还没有通过网络搜索找到一篇文章。如果问题确实代表了一个缺陷,那么让我感到惊讶的是,并不是很多开发人员受到影响。
回答:
任何获取CTRL + C的程序的行为都取决于该程序。通常行为是退出,但一些程序可能会放弃一些内部程序而不是停止整个程序。这甚至有可能(尽管可能被认为是不礼貌的做法)让程序完全忽略击键。
程序的行为是由它设置的信号处理程序定义的。 C库提供了默认的信号处理程序(它们在SIGTERM和SIGINT中执行退出操作),但是程序可以提供自己的处理程序来运行。并非所有信号都允许任意响应。例如,SIGSEGV(seg-fault)需要程序退出,尽管它可以配置其信号处理程序来进行核心转储。 SIGKILL根本无法处理(操作系统内核负责它)。
要在Python中定制信号处理程序,您需要使用标准库中的the signal
module。您可以拨打signal.signal
为系统C库定义的任何信号设置您自己的信号处理函数。键入CTRL + C将在任何基于UNIX的系统上发送SIGINT,所以这可能是您想要处理的内容,如果您想要自己的行为。
尝试是这样的:
import signal import sys
import time
def interrupt_handler(sig, frame):
sys.exit(1)
signal.signal(signal.SIGINT, interrupt_handler)
time.sleep(100)
如果您运行此脚本,用CTRL + C中断它,它应该默默退出,就像你的bash脚本一样。
以上是 python SIGINT不终止调用外壳 的全部内容, 来源链接: utcz.com/qa/260835.html