将KeyboardInterrupt指向子进程

时间:2016-07-20 18:16:37

标签: python subprocess

我希望在Python中启动一个相当长时间运行的子流程,并希望能够使用^C来终止它。但是,按^C会导致父母接收KeyboardInterrupt并终止(有时会将sleep作为已解散的过程)。

import subprocess
subprocess.call("sleep 100".split())

如何按下^C只会终止sleep进程(就像我们在shell命令行中所做的那样),并允许父进程继续?我相信我尝试了将preexec_fnstart_new_sessionshell标记用于call的一些组合,但没有成功。

编辑:我知道我可以在subprocess块中包装try-catch调用,并忽略键盘中断;但我不想那样做。我的问题是:键盘中断应该已经杀死了sleep,应该已经结束了它。为什么然后将其传播给父母。或者是sleep进程从来不是接收中断的进程?如果没有,我将如何将其作为前台进程?

同样,我正在尝试模拟命令行的父子关系。如果我要在命令行上执行等效操作,我可以在不需要额外处理的情况下离开。

3 个答案:

答案 0 :(得分:1)

使用signal来捕获SIGINT,并使信号处理程序终止子进程。

请查看此信息以获取更多信息(如果它适用于Python 2.x):

https://docs.python.org/2/library/signal.html

答案 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)