我正在使用以下命令启动子进程:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
但是,当我尝试使用时杀死:
p.terminate()
要么
p.kill()
该命令在后台继续运行,所以我想知道如何实际终止该进程。
请注意,当我运行命令时:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
它在发布p.terminate()
时成功终止。
使用process group以便能够向组中的所有进程发送信号。为此,您应该将session id附加到衍生/子进程的父进程,这是您的情况下的shell。这将使其成为流程的组长。现在,当信号发送给进程组负责人时,它会被传输到该组的所有子进程。
这是代码:
import os
import signal
import subprocess
# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before exec() to run the shell.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE,
shell=True, preexec_fn=os.setsid)
os.killpg(os.getpgid(pro.pid), signal.SIGTERM) # Send the signal to all the process groups
将信号发送到组中的所有进程
self.proc = Popen(commands,
stdout=PIPE,
stderr=STDOUT,
universal_newlines=True,
preexec_fn=os.setsid)
os.killpg(os.getpgid(self.proc.pid), signal.SIGHUP)
os.killpg(os.getpgid(self.proc.pid), signal.SIGTERM)
我在这里没有看到这个,所以我把它放在那里以防有人需要它。如果您只想确保子进程成功终止,则可以将其放在上下文管理器中。例如,我希望我的标准打印机打印输出图像,并使用上下文管理器确保子进程终止。
import subprocess
with open(filename,'rb') as f:
img=f.read()
with subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE) as lpr:
lpr.stdin.write(img)
print('Printed image...')
我相信这种方法也是跨平台的。
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()
p.kill()
最终杀死了shell进程,cmd
仍在运行。
我找到了一个方便的解决方法:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
这将导致cmd继承shell进程,而不是让shell启动子进程,而不会被杀死。 p.pid
将是你的cmd进程的id。
p.kill()
应该工作。
我不知道这会对你的烟斗产生什么影响。
如果你可以使用psutil,那么这很有效:
import subprocess
import psutil
def kill(proc_pid):
process = psutil.Process(proc_pid)
for proc in process.children(recursive=True):
proc.kill()
process.kill()
proc = subprocess.Popen(["infinite_app", "param"], shell=True)
try:
proc.wait(timeout=3)
except subprocess.TimeoutExpired:
kill(proc.pid)
我可以用它做
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
它杀死了cmd.exe
和我给出命令的程序。
(在Windows上)
当shell=True
shell是子进程时,命令就是它的子进程。所以任何SIGTERM
或SIGKILL
都会杀死shell而不是它的子进程,我不记得一个好方法。我能想到的最好的方法是使用shell=False
,否则当你杀死父shell进程时,它会留下一个已经失效的shell进程。
这些答案都不适合我,所以我离开了有效的代码。在我的情况下,即使用.kill()
杀死进程并获得.poll()
返回代码后,该过程也没有终止。
继subprocess.Popen
documentation之后:
“...为了正确清理一个表现良好的应用程序应该杀死子进程并完成通信......”
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
在我的情况下,我在调用proc.communicate()
之后错过了proc.kill()
。这会清除进程stdin,stdout ......并终止进程。
正如Sai所说,shell是孩子,所以信号被它截获 - 我发现的最好方法是使用shell = False并使用shlex来拆分命令行:
if isinstance(command, unicode):
cmd = command.encode('utf8')
args = shlex.split(cmd)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
那么p.kill()和p.terminate()应该如你所愿。
我觉得我们可以使用:
import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
这不会杀死你的所有任务,而是使用p.pid杀死进程
我知道这是一个老问题,但这可能有助于寻找不同方法的人。这就是我在windows上用来杀死我调用过程的东西。
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)
/ IM是图像名称,如果需要,也可以执行/ PID。 / T杀死进程以及子进程。 / F force终止它。 si,就像我设置的那样,你是如何在不显示CMD窗口的情况下完成此操作的。此代码用于python 3。