我在Python中调用一个shell脚本,它会生成多个子进程。如果两分钟后没有完成,我想终止该过程及其所有孩子。
有什么方法可以用subprocess.run做到这一点,还是我必须回到使用Popen?由于运行阻塞,我无法在某个地方保存pid以在额外命令中杀死子进程。一个简短的代码示例:
try:
subprocess.run(["my_shell_script"], stderr=subprocess.STDOUT, timeout=120)
except subprocess.TimeoutExpired:
print("Timeout during execution")
答案 0 :(得分:1)
此问题已向Python开发人员报告为bug。当stderr或stdout重定向时,这似乎特别发生。 这是@Tanu代码的更正确版本。
import subprocess as sp
try:
proc = sp.Popen(['ls', '-l'], stdout=sp.PIPE, stderr=sp.PIPE)
outs, errs = proc.communicate(timeout=120)
except sp.TimeoutExpired:
proc.terminate()
Popen不接受timeout
作为参数。必须将其传递到communicate
。
在Posix操作系统上,terminate
比kill
更柔和,因为它降低了创建僵尸进程的风险。
答案 1 :(得分:0)
引用文档:
subprocess.run - 默认情况下,它不捕获stdout或stderr。为此,请为stdout和/或stderr参数传递PIPE。
如果你不想,不必使用Popen()。模块中的其他函数,例如.call(),. Popen()。
有三个'文件'流:输入的stdin,输出的stdout和stderr。应用程序决定在哪里写;通常是stderr的错误和诊断信息,其余的是stdout。要捕获这些输出中的任何一个的输出,请指定subprocess.PIPE参数,以便将“stream”重定向到您的程序中。
超时后终止子进程:
import os
import signal
import subprocess
try:
proc = subprocess.Popen(["ls", "-l"], stdout=PIPE, stderr=PIPE, timeout=120)
except subprocess.TimeoutExpired:
os.kill(proc.pid, signal.SIGTERM)