Windows 上的 Python 2.6:如何使用“shell=True”参数终止 subprocess.Popen?

Posted

技术标签:

【中文标题】Windows 上的 Python 2.6:如何使用“shell=True”参数终止 subprocess.Popen?【英文标题】:Python 2.6 on Windows: how to terminate subprocess.Popen with "shell=True" argument? 【发布时间】:2010-10-16 07:56:07 【问题描述】:

有没有办法终止以 subprocess.Popen 类启动的进程,并将“shell”参数设置为“True”?在下面的最小工作示例中(使用 wxPython),您可以愉快地打开和终止记事本进程,但是如果您将 Popen“shell”参数更改为“True”,那么记事本进程不会终止。

import wx
import threading
import subprocess

class MainWindow(wx.Frame):

    def __init__(self, parent, id, title):        
        wx.Frame.__init__(self, parent, id, title)
        self.main_panel = wx.Panel(self, -1)

        self.border_sizer = wx.BoxSizer()

        self.process_button = wx.Button(self.main_panel, -1, "Start process", (50, 50))
        self.process_button.Bind(wx.EVT_BUTTON, self.processButtonClick)

        self.border_sizer.Add(self.process_button)
        self.main_panel.SetSizerAndFit(self.border_sizer)
        self.Fit()

        self.Centre()
        self.Show(True)

    def processButtonClick(self, event):
        if self.process_button.GetLabel() == "Start process":
            self.process_button.SetLabel("End process")
            self.notepad = threading.Thread(target = self.runProcess)
            self.notepad.start()
        else:
            self.cancel = 1
            self.process_button.SetLabel("Start process")

    def runProcess(self):
        self.cancel = 0

        notepad_process = subprocess.Popen("notepad", shell = False)

        while notepad_process.poll() == None: # While process has not yet terminated.
            if self.cancel:
                notepad_process.terminate()
                break

def main():
    app = wx.PySimpleApp()
    mainView = MainWindow(None, wx.ID_ANY, "test")
    app.MainLoop()

if __name__ == "__main__":
    main()

为了这个问题,请接受“shell”确实必须等于“True”。

【问题讨论】:

哪个版本的 Python? 相关:How to terminate a python subprocess launched with shell=True 【参考方案1】:

当使用 shell=True 并在进程上调用终止时,您实际上是在杀死 shell,而不是记事本进程。 shell 可以是 COMSPEC 环境变量中指定的任何内容。

我能想到杀死这个记事本进程的唯一方法是使用 Win32process.EnumProcesses() 搜索该进程,然后使用 win32api.TerminateProcess 杀死它。但是,您将无法将记事本进程与其他同名进程区分开来。

【讨论】:

【参考方案2】:

Python 2.6 有一个针对 subprocess.Popen 对象的 kill 方法。

http://docs.python.org/library/subprocess.html#subprocess.Popen.kill

【讨论】:

文档说 kill 是 Windows 平台上终止的别名。那就是他在示例中使用的不起作用。 @nosklo:你测试过这个吗?我无法测试它;我没有在 Windows 上安装 2.6。 @S.Lott 如果您无法测试它,为什么要发布答案? :) 它不起作用。【参考方案3】:

你为什么使用shell=True

只是不要这样做。你不需要它,它会调用 shell,这没用。

我不接受它必须是True,因为它不是。使用shell=True 只会给你带来问题,没有任何好处。只是不惜一切代价避免它。除非你正在运行一些 shell 内部命令,否则你不需要它,永远

【讨论】:

【参考方案4】:

根据 Thomas Watnedal 的回答中给出的提示,他指出在示例中实际上只有 shell 被杀死,我根据 Mark 中给出的示例安排了以下函数来解决我的场景中的问题Hammond 的 PyWin32 库:

procname 是在任务管理器中看到的进程的名称,不带扩展名,例如FFMPEG.EXE 将是 killProcName("FFMPEG")。请注意,该函数相当慢,因为它会枚举所有当前正在运行的进程,因此结果不是即时的。

import win32api
import win32pdhutil
import win32con

def killProcName(procname):
    """Kill a running process by name.  Kills first process with the given name."""
    try:
        win32pdhutil.GetPerformanceAttributes("Process", "ID Process", procname)
    except:
        pass

    pids = win32pdhutil.FindPerformanceAttributesByName(procname)

    # If _my_ pid in there, remove it!
    try:
        pids.remove(win32api.GetCurrentProcessId())
    except ValueError:
        pass

    handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pids[0])
    win32api.TerminateProcess(handle, 0)
    win32api.CloseHandle(handle)

【讨论】:

-1:solutuion 杀死碰巧以相同名称运行的其他进程。 正如我所说,该解决方案适用于我的特定场景,在这种情况下,我需要杀死的进程始终只有一个正在运行的实例。 另外,代码中说每个实例都被杀死的注释是不正确的,我已经更新了它。【参考方案5】:

如果您确实需要shell=True 标志,那么解决方案是使用带有/WAIT 标志的start shell 命令。使用此标志,start 进程将等待其子进程终止。然后,例如使用 psutil 模块,您可以通过以下顺序实现您想要的:

>>> import psutil
>>> import subprocess
>>> doc = subprocess.Popen(["start", "/WAIT", "notepad"], shell=True)
>>> doc.poll()
>>> psutil.Process(doc.pid).get_children()[0].kill()
>>> doc.poll()
0
>>> 

在第三行之后出现记事本。只要窗口由于/WAIT 标志而打开,poll 就会返回None。杀死start的子记事本窗口后消失,poll返回退出码。

【讨论】:

以上是关于Windows 上的 Python 2.6:如何使用“shell=True”参数终止 subprocess.Popen?的主要内容,如果未能解决你的问题,请参考以下文章

如何在同一个 Windows XP 机器上同时运行 python 2.6 和 3.0?

带有 python 2.7 的 Windows 上的 Readline 功能

pymysql.connect 命令使 Windows 上的 python shell 崩溃

安装 Python sikuli 包(安装 pyjnius 的问题) Windows 7 Python 2.6

Python 2.6 Win32 (xp) 上的 Python 多处理

Ubuntu 上的 Python 2.6 导入包 (psyco)