Is there a way to terminate a process started with the subprocess.Popen class with the "shell" argument set to "True"? In the working minimal example below (uses wxPython) you can open and terminate a Notepad process happily, however if you change the Popen "shell" argument to "True" then the Notepad process doesn't terminate.
有没有办法终止使用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()
Please accept for the sake of this question that "shell" does have to equal "True".
请接受这个问题,“shell”必须等于“True”。
5 个解决方案
#1
Why are you using shell=True
?
你为什么用shell = True?
Just don't do it. You don't need it, it invokes the shell and that is useless.
只是不要这样做。你不需要它,它调用shell,这是没用的。
I don't accept it has to be True
, because it doesn't. Using shell=True
only brings you problems and no benefit. Just avoid it at all costs. Unless you're running some shell internal command, you don't need it, ever.
我不接受它必须是真的,因为它没有。使用shell = True只会给你带来问题并没有任何好处。不惜一切代价避免它。除非你运行一些shell内部命令,否则你不需要它。
#2
When using shell=True and calling terminate on the process, you are actually killing the shell, not the notepad process. The shell would be whatever is specified in the COMSPEC environment variable.
当使用shell = True并在进程上调用terminate时,实际上是在杀死shell而不是记事本进程。 shell将是COMSPEC环境变量中指定的任何内容。
The only way I can think of killing this notepad process would be to use Win32process.EnumProcesses() to search for the process, then kill it using win32api.TerminateProcess. You will however not be able to distinguish the notepad process from other processes with the same name.
我能想到杀死这个记事本进程的唯一方法是使用Win32process.EnumProcesses()来搜索进程,然后使用win32api.TerminateProcess将其终止。但是,您无法将记事本进程与具有相同名称的其他进程区分开来。
#3
Based on the tip given in Thomas Watnedal's answer, where he points out that just the shell is actually being killed in the example, I have arranged the following function which solves the problem for my scenario, based on the example given in Mark Hammond's PyWin32 library:
根据Thomas Watnedal的回答中给出的提示,他指出实际上只是shell被杀死了,我已经安排了以下函数,根据Mark Hammond的PyWin32库中给出的示例解决了我的场景问题:
procname is the name of the process as seen in Task Manager without the extension, e.g. FFMPEG.EXE would be killProcName("FFMPEG"). Note that the function is reasonably slow as it performs enumeration of all current running processes so the result is not instant.
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)
#4
If you really need the shell=True
flag, then the solution is to use the start
shell command with the /WAIT
flag. With this flag, the start
process will wait for its child to terminate. Then, using for example the psutil
module you can achieve what you want with the following sequence:
如果你真的需要shell = True标志,那么解决方案是使用带有/ WAIT标志的start shell命令。使用此标志,启动进程将等待其子进程终止。然后,使用例如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
>>>
After the third line Notepad appears. poll
returns None
as long as the window is open thanks to the /WAIT
flag. After killing start
's child Notepad window disappears, and poll
returns the exit code.
第三行记事本出现后。 poll返回None,只要窗口打开,由于/ WAIT标志。杀死启动之后,子记事本窗口消失,并且轮询返回退出代码。
#5
Python 2.6 has a kill method for subprocess.Popen objects.
Python 2.6为subprocess.Popen对象提供了kill方法。
http://docs.python.org/library/subprocess.html#subprocess.Popen.kill
#1
Why are you using shell=True
?
你为什么用shell = True?
Just don't do it. You don't need it, it invokes the shell and that is useless.
只是不要这样做。你不需要它,它调用shell,这是没用的。
I don't accept it has to be True
, because it doesn't. Using shell=True
only brings you problems and no benefit. Just avoid it at all costs. Unless you're running some shell internal command, you don't need it, ever.
我不接受它必须是真的,因为它没有。使用shell = True只会给你带来问题并没有任何好处。不惜一切代价避免它。除非你运行一些shell内部命令,否则你不需要它。
#2
When using shell=True and calling terminate on the process, you are actually killing the shell, not the notepad process. The shell would be whatever is specified in the COMSPEC environment variable.
当使用shell = True并在进程上调用terminate时,实际上是在杀死shell而不是记事本进程。 shell将是COMSPEC环境变量中指定的任何内容。
The only way I can think of killing this notepad process would be to use Win32process.EnumProcesses() to search for the process, then kill it using win32api.TerminateProcess. You will however not be able to distinguish the notepad process from other processes with the same name.
我能想到杀死这个记事本进程的唯一方法是使用Win32process.EnumProcesses()来搜索进程,然后使用win32api.TerminateProcess将其终止。但是,您无法将记事本进程与具有相同名称的其他进程区分开来。
#3
Based on the tip given in Thomas Watnedal's answer, where he points out that just the shell is actually being killed in the example, I have arranged the following function which solves the problem for my scenario, based on the example given in Mark Hammond's PyWin32 library:
根据Thomas Watnedal的回答中给出的提示,他指出实际上只是shell被杀死了,我已经安排了以下函数,根据Mark Hammond的PyWin32库中给出的示例解决了我的场景问题:
procname is the name of the process as seen in Task Manager without the extension, e.g. FFMPEG.EXE would be killProcName("FFMPEG"). Note that the function is reasonably slow as it performs enumeration of all current running processes so the result is not instant.
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)
#4
If you really need the shell=True
flag, then the solution is to use the start
shell command with the /WAIT
flag. With this flag, the start
process will wait for its child to terminate. Then, using for example the psutil
module you can achieve what you want with the following sequence:
如果你真的需要shell = True标志,那么解决方案是使用带有/ WAIT标志的start shell命令。使用此标志,启动进程将等待其子进程终止。然后,使用例如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
>>>
After the third line Notepad appears. poll
returns None
as long as the window is open thanks to the /WAIT
flag. After killing start
's child Notepad window disappears, and poll
returns the exit code.
第三行记事本出现后。 poll返回None,只要窗口打开,由于/ WAIT标志。杀死启动之后,子记事本窗口消失,并且轮询返回退出代码。
#5
Python 2.6 has a kill method for subprocess.Popen objects.
Python 2.6为subprocess.Popen对象提供了kill方法。
http://docs.python.org/library/subprocess.html#subprocess.Popen.kill