2009-03-30 1 views
7

Есть ли способ завершить процесс, запущенный с помощью подпроцесса. Открытый класс с аргументом «shell», установленным в «True»? В рабочем минимальном примере ниже (используется wxPython) вы можете успешно открыть и завершить процесс Notepad, однако, если вы измените аргумент «shell» Popen на «True», процесс Notepad не завершится.Python 2.6 на Windows: как завершить подпроцесс.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() 

Примите, пожалуйста, ради этого вопроса, что «оболочка» должна быть равна «True».

+0

Какая версия Python? –

+1

related: [Как завершить подпроцесс python, запущенный с помощью оболочки = True] (http: // stackoverflow.com/questions/4789837/how-to-terminate-a-python-subprocess-launch-with-shell-true) – jfs

ответ

2

Основываясь на подсказке, приведенной в ответе Томаса Уотнедаля, где он указывает, что в этом случае фактически убивается оболочка, я организовал следующую функцию, которая решает проблему для моего сценария, на основе примера, приведенного в Библиотека 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

-1: solutuion убивает другие процессы, которые выполняются с тем же именем. – nosklo

+0

Как я уже сказал, решение работает для моего конкретного сценария, и в этом случае всегда будет только один исполняемый экземпляр процесса, который мне нужно убить. –

+0

Также комментарий в коде, в котором говорится, что каждый экземпляр убит, был неправильным, и я его обновил. –

5

При использовании оболочки = Истина и вызов завершаются в процессе, вы фактически убиваете оболочку, а не процесс блокнота. Оболочка будет указана в переменной среды COMSPEC.

Единственный способ, которым я могу думать об убийстве этого процесса в блокноте, это использовать Win32process.EnumProcesses() для поиска процесса, а затем убить его с помощью win32api.TerminateProcess. Однако вы не сможете отличить процесс блокнота от других процессов с тем же именем.

-1

У Python 2.6 есть метод kill для subprocess.Popen объектов.

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

+0

В документации говорится, что kill - это псевдоним для завершения на платформе Windows. То, что он использует в примере, который не работает. –

+2

-1: метод kill убьет оболочку, а не решение – nosklo

+0

@nosklo: вы протестировали это? Я не могу это проверить; У меня нет 2.6, установленного в Windows. –

8

Почему вы используете shell=True?

Только не делайте этого. Он вам не нужен, он вызывает оболочку, и это бесполезно.

Я не принимаю Это должно быть True, потому что это не так. Использование shell=True только приносит вам проблемы и никакой пользы. Просто избегайте этого любой ценой. Если вы не используете внутреннюю команду оболочки, она вам не нужна, когда-либо.

0

Если вам действительно нужно shell=True флаг, то решение использовать команду start оболочки с /WAIT флагом. С помощью этого флага процесс 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 ребенок «Блокнот» исчезает, а возвращает код выхода.

Смежные вопросы