我希望在Python中启动一个相当长时间运行的子流程,并希望能够使用^C
来终止它。但是,按^C
会导致父母接收KeyboardInterrupt
并终止(有时会将sleep
作为已解散的过程)。
import subprocess
subprocess.call("sleep 100".split())
如何按下^C
只会终止sleep
进程(就像我们在shell命令行中所做的那样),并允许父进程继续?我相信我尝试了将preexec_fn
,start_new_session
和shell
标记用于call
的一些组合,但没有成功。
编辑:我知道我可以在subprocess
块中包装try-catch
调用,并忽略键盘中断;但我不想那样做。我的问题是:键盘中断应该已经杀死了sleep
,应该已经结束了它。为什么然后将其传播给父母。或者是sleep
进程从来不是接收中断的进程?如果没有,我将如何将其作为前台进程?
同样,我正在尝试模拟命令行的父子关系。如果我要在命令行上执行等效操作,我可以在不需要额外处理的情况下离开。
答案 0 :(得分:1)
使用signal
来捕获SIGINT,并使信号处理程序终止子进程。
请查看此信息以获取更多信息(如果它适用于Python 2.x):
答案 1 :(得分:0)
不确定它是否是一种解决方法,但它运行正常(至少在Windows上以不同的方式处理CTRL + C)
import subprocess
try:
subprocess.call(r"C:\msys64\usr\bin\sleep 100".split())
except KeyboardInterrupt:
print("** BREAK **")
print("continuing the python program")
执行:
K:\jff\data\python>dummy_wait.py
** BREAK **
continuing the python program
答案 2 :(得分:0)
正如雅各布所建议的,一种方式(感谢同事)要处理SIGNAL并将其传递给孩子。所以像这样的包装器将是:
import signal
import subprocess
def run_cmd(cmd, **kwargs):
try:
p = None
# Register handler to pass keyboard interrupt to the subprocess
def handler(sig, frame):
if p:
p.send_signal(signal.SIGINT)
else:
raise KeyboardInterrupt
signal.signal(signal.SIGINT, handler)
p = subprocess.Popen(cmd, **kwargs)
if p.wait():
raise Exception(cmd[0] + " failed")
finally:
# Reset handler
signal.signal(signal.SIGINT, signal.SIG_DFL)