目标 KeyboardInterrupt 到子进程
Target KeyboardInterrupt to subprocess
我希望在 Python 中启动一个相当长的 运行 子进程,并希望能够用 ^C
终止它。但是,按 ^C
会导致父级接收 KeyboardInterrupt
并终止(有时会使 sleep
成为一个不存在的进程)。
import subprocess
subprocess.call("sleep 100".split())
我如何才能按下 ^C
仅终止 sleep
进程(就像我们在 shell 命令行上所做的那样),并允许父级继续?我相信我尝试了一些使用 preexec_fn
、start_new_session
和 shell
标志到 call
的组合,但没有成功。
Edit:我知道我可以将 subprocess
调用包装在 try-catch
块中,并忽略键盘中断;但我不想那样做。我的问题是:键盘中断应该杀死 sleep
,并且应该结束它。可以说,为什么然后传播到父级。还是 sleep
进程从来都不是接收中断的进程?如果不是,我如何让它成为前台进程?
同样,我正在尝试模拟命令行的父子关系。如果我在命令行上执行相同的操作,则无需额外处理即可离开。
使用signal
捕获SIGINT,并使信号处理程序终止子进程。
查看此以获取更多信息(如果它适用于 Python 2.x):
不确定这是否是一种解决方法,但它工作正常(至少在 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
正如 Jacob 所建议的,一种方法(感谢一位同事)是处理 SIGNAL 并将其传递给 child。所以像这样的包装器将是:
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)
我希望在 Python 中启动一个相当长的 运行 子进程,并希望能够用 ^C
终止它。但是,按 ^C
会导致父级接收 KeyboardInterrupt
并终止(有时会使 sleep
成为一个不存在的进程)。
import subprocess
subprocess.call("sleep 100".split())
我如何才能按下 ^C
仅终止 sleep
进程(就像我们在 shell 命令行上所做的那样),并允许父级继续?我相信我尝试了一些使用 preexec_fn
、start_new_session
和 shell
标志到 call
的组合,但没有成功。
Edit:我知道我可以将 subprocess
调用包装在 try-catch
块中,并忽略键盘中断;但我不想那样做。我的问题是:键盘中断应该杀死 sleep
,并且应该结束它。可以说,为什么然后传播到父级。还是 sleep
进程从来都不是接收中断的进程?如果不是,我如何让它成为前台进程?
同样,我正在尝试模拟命令行的父子关系。如果我在命令行上执行相同的操作,则无需额外处理即可离开。
使用signal
捕获SIGINT,并使信号处理程序终止子进程。
查看此以获取更多信息(如果它适用于 Python 2.x):
不确定这是否是一种解决方法,但它工作正常(至少在 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
正如 Jacob 所建议的,一种方法(感谢一位同事)是处理 SIGNAL 并将其传递给 child。所以像这样的包装器将是:
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)