Pergunta

Existe uma maneira de encerrar um processo iniciado com a classe subprocess.Popen com o "shell" set argumento para "True"? No exemplo mínima trabalhando abaixo (usa wxPython) você pode abrir e encerrar um processo Notepad feliz, no entanto, se você alterar o argumento Popen "shell" para "True", em seguida, o processo de bloco de notas não terminar.

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()

Por favor, aceite por causa desta questão que "shell" tem que ser igual "True".

Foi útil?

Solução 3

Com base na dica dada resposta de Thomas Watnedal, onde ele aponta que apenas o shell está realmente sendo mortos no exemplo, eu arranjei a função após o que resolve o problema para o meu cenário, com base no exemplo dado em Marcos biblioteca PyWin32 de Hammond:

procname é o nome do processo, como visto no Gerenciador de tarefas sem a extensão, por exemplo, FFMPEG.EXE seria killProcName ( "FFMPEG"). Note-se que a função é razoavelmente lento como ele executa a enumeração de todos os processos em execução atuais de modo que o resultado não é imediato.

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)

Outras dicas

Por que você está usando shell=True?

Apenas não fazê-lo. Você não precisa dele, ele chama o shell e que é inútil.

Eu não aceito que tem que ser True, porque isso não acontece. Usando shell=True só traz-lhe problemas e nenhum benefício. Apenas evitá-lo a todo custo. A menos que você estiver executando algum comando interno de shell, você não precisa dele, sempre .

Ao usar shell = true e chamando terminará no processo, você está realmente matando o shell, e não o processo de bloco de notas. O escudo seria tudo o que está especificado na variável de ambiente COMSPEC.

A única maneira que eu posso pensar de matar esse processo notepad seria usar Win32process.EnumProcesses () para procurar o processo, e depois matá-lo usando win32api.TerminateProcess. Você no entanto, não será capaz de distinguir o processo de bloco de notas de outros processos com o mesmo nome.

Se você realmente precisa a bandeira shell=True, então a solução é usar o comando shell start com a bandeira /WAIT. Com este sinalizador, o processo start vai esperar por seu filho terminar. Em seguida, usando por exemplo, o psutil módulo que você pode conseguir o que você quer com a sequência seguinte:

>>> 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
>>> 

Depois da terceira linha Notepad aparece. poll retornos None enquanto a janela estiver aberta graças à bandeira /WAIT. Depois de matar desaparece janela Notepad filho de start e poll retorna o código de saída.

Python 2.6 tem um método kill objetos subprocess.Popen.

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top