Windows上的Python 2.6:如何终止subprocess.Popen与“壳=真”参数?

有没有办法终止一个启动与“shell”参数设置为“True”的subprocess.Popen类的进程? 在下面的工作最小的例子中(使用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() 

为了这个问题请接受,“壳”必须等于“真”。

Solutions Collecting From Web of "Windows上的Python 2.6:如何终止subprocess.Popen与“壳=真”参数?"

你为什么使用shell=True

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

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

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

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

基于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) 

如果你真的需要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 >>> 

第三行记事本出现后。 只要窗口打开, poll返回None ,这要归功于/WAIT标志。 查杀start的小孩记事本窗口消失后, poll返回退出代码。

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

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