我正在启动一个带有以下命令的子过程:

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

但是,当我尝试使用以下方式杀死时:

p.terminate()

或者

p.kill()

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

请注意,当我运行命令时:

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

发行时确实成功终止 p.terminate().

有帮助吗?

解决方案

用一个 过程组 为了使小组中的所有过程向所有过程发送信号。为此,您应该附上一个 会话ID 到产卵/子过程的父进程,这是您的情况。这将使它成为流程的小组负责人。因此,现在,当信号发送给流程组负责人时,它将传输到该组的所有子进程。

这是代码:

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() 最终杀死了外壳过程, cmd 仍在运行。

我发现了一个方便的解决方法:

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

这将导致CMD继承壳的过程,而不是让壳启动儿童过程,这不会被杀死。 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 外壳是子过程,命令是其孩子。所以有 SIGTERM 或者 SIGKILL 会杀死外壳,但不会杀死其子过程,我不记得是这样做的好方法。我能想到的最好的方法是使用 shell=False, ,否则,当您杀死父壳过程时,它将留下已解决的外壳过程。

这些答案对我不起作用,所以我离开了确实有效的代码。就我而言,即使在杀死了这个过程之后 .kill() 并得到一个 .poll() 返回代码该过程没有终止。

跟随 subprocess.Popen 文档:

“ ...为了正确清理行为良好的申请,应杀死儿童过程并完成沟通……”

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 = 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力终止它。我设置的Si是您在不显示CMD窗口的情况下执行此操作的方式。该代码在Python 3中使用。

将信号发送到组中的所有过程

    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...')

我相信这种方法也是跨平台。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top