如何终止使用 shell=True 启动的 python 子进程

2024-11-21 08:33:00
admin
原创
5
摘要:问题描述:我正在使用以下命令启动子进程:p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 但是,当我尝试使用以下方法杀死它时:p.terminate() 或者p.kill() 该命令一直在后台运行,所以我想知道如何才能真正终止该进程。请...

问题描述:

我正在使用以下命令启动子进程:

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

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

p.terminate()

或者

p.kill()

该命令一直在后台运行,所以我想知道如何才能真正终止该进程。

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

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

当发出时它确实成功终止p.terminate()


解决方案 1:

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

解决方案 2:

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()应该可以。

但我不知道这会对你的管道产生什么影响。

解决方案 3:

如果你可以使用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)

解决方案 4:

我可以用它

from subprocess import Popen

process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))

它杀死了cmd.exe我所命令的程序。

(在 Windows 上)

解决方案 5:

shell=Trueshell 是子进程,而命令是其子进程时。因此,任何SIGTERMSIGKILL都会终止 shell 但不会终止其子进程,我不记得有什么好的方法可以做到这一点。我能想到的最好的方法是使用shell=False,否则当您终止父 shell 进程时,它将留下一个已停用的 shell 进程。

解决方案 6:

这些答案对我都不起作用,所以我保留了有效的代码。在我的情况下,即使使用 终止进程.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...并终止该进程。

解决方案 7:

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

解决方案 8:

向组内所有进程发送信号

    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)

解决方案 9:

对于 Python 3.5+,有一个非常简单的方法(实际上在 Python 3.8 上测试过)。

import subprocess, signal, time
p = subprocess.Popen(['cmd'], shell=True)
time.sleep(5) #Wait 5 secs before killing
p.send_signal(signal.CTRL_C_EVENT)

然后,如果您有键盘输入检测或类似的东西,您的代码可能会在某个时候崩溃。在这种情况下,在出现错误的代码/函数行上,只需使用:

try:
    FailingCode #here goes the code which is raising KeyboardInterrupt
except KeyboardInterrupt:
    pass

这段代码所做的只是向正在运行的进程发送“ CTRL+ C”信号,这将导致进程被终止。

解决方案 10:

对我有用的解决方案

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

解决方案 11:

完整的解决方案,在超时或特定条件下通过回调函数终止正在运行的进程(包括子树)。适用于 Windows 和 Linux,从 Python 2.7 到 3.12,以及截至撰写本文时 pypy 3.6 到 pypy 3.10,有关更多信息,请参阅https://github.com/netinvent/command_runner

安装pip install command_runner

超时示例:

from command_runner import command_runner

# Kills ping after 2 seconds
exit_code, output = command_runner('ping 127.0.0.1', shell=True, timeout=2)

特定条件的示例:如果当前系统时间秒数大于 5,我们将停止 ping

from time import time
from command_runner import command_runner

def my_condition():
    # Arbitrary condition for demo
    return True if int(str(int(time()))[-1]) > 5

# Calls my_condition() every second (check_interval) and kills ping if my_condition() returns True
exit_code, output = command_runner('ping 127.0.0.1', shell=True, stop_on=my_condition, check_interval=1)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用