我试着从管道的另一边接收信号,但我似乎接收不到任何信号
这个程序是用来捕捉
#! /usr/bin/python
import signal
import sys
from time import sleep
def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
sys.exit(0)
for i in [x for x in dir(signal) if x.startswith("SIG")]:
try:
signum = getattr(signal,i)
signal.signal(signum,signal_handler)
except (OSError, RuntimeError) as m: #OSError for Python3, RuntimeError for 2
print ("Skipping {}".format(i))
except ValueError:
print ("Value skip {}".format(i))
signal.signal(signal.SIGINT, signal_handler)
for a in range(0, 20):
print a
sleep(1)
字符串
我得到了不同运行方法的不一致行为,我不确定该如何解释它。当我将脚本的输出通过管道传输到tee
时,我无法捕捉到可以干净地结束程序的信号
运行方式:运行脚本,手动Ctrl+C
/sub.py
型
输出量:
Skipping SIGKILL
Skipping SIGSTOP
Value skip SIG_DFL
0
1
2
3
4
^CYou pressed Ctrl+C!
型
运行方法(运行脚本并使用kill -13
(BROKEN_PIPE)杀死):
输出量:
Skipping SIGKILL
Skipping SIGSTOP
Value skip SIG_DFL
0
1
2
3
4
You pressed Ctrl+C!
型
运行方法(使用管道连接到T形三通和Ctrl+C运行脚本):
/sub.py | tee
型
输出量:
Skipping SIGKILL
Skipping SIGSTOP
Value skip SIG_DFL
0
^CTraceback (most recent call last):
File "/sub.py", line 24, in <module>
sleep(1)
型
或
Skipping SIGKILL
Skipping SIGSTOP
Value skip SIG_DFL
0
1
2
3
4
^C
型
注意,在这两种情况下都没有调用signal_handler
方法。
为什么没有调用信号处理程序?是否有一个信号我可以捕捉到优雅退出?
python --version
Python 2.7.17
bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
1条答案
按热度按时间xam8gpfp1#
这个答案主要针对python 3.7+(在这里讨论),但我想python 2.7也是如此。
在信号处理程序中调用
print
或在stdout
上使用未刷新的数据调用sys.exit()
都不起作用,因为到那时,tee
已经停止,stdout
管道已经损坏(当您Ctrl-C
管道时会发生什么,请参见here)。我认为最简单的解决方法是避免使用你打算中断的管道。你可以通过使用
tail
而不是tee
来实现这一点:字符串
如果你确实想让shell管道工作,你可以尝试重写你的信号处理程序,把你的消息和未刷新的
stdout
数据写到一个像这样的文件中:型
这里需要注意的是,这个解决方案可能有一个小的竞争条件。如果
stdout
管道首先被破坏,然后你的程序在收到SIGTERM
信号之前尝试刷新到stdout
,你可能会得到一个BrokenPipeError
,然后是一个SIGTERM
信号,这将是一个混乱的尝试处理。