Linux 如何终止使用 shell=True 启动的 python 子进程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4789837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to terminate a python subprocess launched with shell=True
提问by user175259
I'm launching a subprocess with the following command:
我正在使用以下命令启动一个子进程:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
However, when I try to kill using:
但是,当我尝试使用以下方法杀死时:
p.terminate()
or
或者
p.kill()
The command keeps running in the background, so I was wondering how can I actually terminate the process.
该命令一直在后台运行,所以我想知道如何才能真正终止该进程。
Note that when I run the command with:
请注意,当我使用以下命令运行命令时:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
It does terminate successfully when issuing the p.terminate()
.
发出p.terminate()
.
采纳答案by mouad
Use a process groupso as to enable sending a signal to all the process in the groups. For that, you should attach a session idto the parent process of the spawned/child processes, which is a shell in your case. This will make it the group leader of the processes. So now, when a signal is sent to the process group leader, it's transmitted to all of the child processes of this group.
使用进程组以便能够向组中的所有进程发送信号。为此,您应该将会话ID附加到衍生/子进程的父进程,在您的情况下它是一个 shell。这将使它成为流程的组长。所以现在,当一个信号被发送到进程组领导时,它被传输到这个组的所有子进程。
Here's the code:
这是代码:
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
回答by Sai Venkat
When shell=True
the shell is the child process, and the commands are its children. So any SIGTERM
or SIGKILL
will kill the shell but not its child processes, and I don't remember a good way to do it.
The best way I can think of is to use shell=False
, otherwise when you kill the parent shell process, it will leave a defunct shell process.
当shell=True
shell 是子进程并且命令是它的子进程时。所以 any SIGTERM
orSIGKILL
会杀死shell而不是它的子进程,我不记得有什么好的方法来做到这一点。我能想到的最好的方法是使用shell=False
,否则当你杀死父shell进程时,它会留下一个不存在的shell进程。
回答by Matt Billenstein
As Sai said, the shell is the child, so signals are intercepted by it -- best way I've found is to use shell=False and use shlex to split the command line:
正如 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)
Then p.kill() and p.terminate() should work how you expect.
然后 p.kill() 和 p.terminate() 应该按照您的预期工作。
回答by Bryant Hansen
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()
p.kill()
ends up killing the shell process and cmd
is still running.
p.kill()
最终杀死shell进程并且cmd
仍在运行。
I found a convenient fix this by:
我通过以下方式找到了一个方便的解决方法:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
This will cause cmd to inherit the shell process, instead of having the shell launch a child process, which does not get killed. p.pid
will be the id of your cmd process then.
这将导致 cmd 继承 shell 进程,而不是让 shell 启动一个不会被杀死的子进程。 p.pid
那么将是您的 cmd 进程的 ID。
p.kill()
should work.
p.kill()
应该管用。
I don't know what effect this will have on your pipe though.
我不知道这会对您的管道产生什么影响。
回答by SPratap
I could do it using
我可以用
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
it killed the cmd.exe
and the program that i gave the command for.
它杀死了cmd.exe
我发出命令的程序。
(On Windows)
(在 Windows 上)
回答by Jovik
If you can use psutil, then this works perfectly:
如果您可以使用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)
回答by epinal
None of this answers worked for me so Im leaving the code that did work. In my case even after killing the process with .kill()
and getting a .poll()
return code the process didn't terminate.
这些答案都不适合我,所以我留下了有效的代码。在我的情况下,即使在杀死进程.kill()
并获得.poll()
返回码后,进程也没有终止。
Following the subprocess.Popen
documentation:
按照subprocess.Popen
文档:
"...in order to cleanup properly a well-behaved application should kill the child process and finish communication..."
“......为了正确清理,一个行为良好的应用程序应该杀死子进程并完成通信......”
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
In my case I was missing the proc.communicate()
after calling proc.kill()
. This cleans the process stdin, stdout ... and does terminate the process.
就我而言,我错过了proc.communicate()
调用proc.kill()
. 这会清除进程 stdin、stdout ... 并终止进程。
回答by Zx4161
I know this is an old question but this may help someone looking for a different method. This is what I use on windows to kill processes that I've called.
我知道这是一个老问题,但这可能有助于寻找不同方法的人。这就是我在 Windows 上用来杀死我调用的进程的方法。
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)
/IM is the image name, you can also do /PID if you want. /T kills the process as well as the child processes. /F force terminates it. si, as I have it set, is how you do this without showing a CMD window. This code is used in python 3.
/IM 是图像名称,如果需要,您也可以使用 /PID。/T 杀死进程以及子进程。/F force 终止它。si,正如我所设置的,是你如何在不显示 CMD 窗口的情况下执行此操作。此代码用于 python 3。
回答by rogers.wang
Send the signal to all the processes in group
向组内所有进程发送信号
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)
回答by Nilesh K.
what i feel like we could use:
我觉得我们可以使用:
import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
this will not kill all your task but the process with the p.pid
这不会终止您的所有任务,而是使用 p.pid 终止进程