我用下面的命令启动一个子进程:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

然而,当我试图杀死使用:

p.terminate()

or

p.kill()

该命令一直在后台运行,因此我想知道如何实际终止该进程。

注意,当我使用以下命令运行时:

p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)

它在发出p.terminate()时成功终止。


当前回答

正如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()应该按您期望的方式工作。

其他回答

当shell=True时,shell是子进程,命令是它的子进程。因此,任何SIGTERM或SIGKILL都会杀死shell,但不会杀死它的子进程,我不记得有什么好方法可以做到这一点。 我能想到的最好的方法是使用shell=False,否则当你杀死父shell进程时,它将留下一个失效的shell进程。

正如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()应该按您期望的方式工作。

这个方法对我很有效

if os.name == 'nt':  # windows
    subprocess.Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
else:
    os.kill(process.pid, signal.SIGTERM)

使用进程组,以便向该组中的所有进程发送信号。为此,您应该将会话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
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()应该工作。

我不知道这会对你的烟斗有什么影响。