8

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

この質問のために、「シェル」は「真」と等しくなければならないことを受け入れてください。

4

5 に答える 5

7

なぜあなたは使用していshell=Trueますか?

やらないでください。あなたはそれを必要としません。それはシェルを呼び出しますが、それは役に立ちません。

そうではないので、私はそれがでなければならないことを受け入れTrueません。使用しshell=Trueても問題が生じるだけで、何のメリットもありません。絶対に避けてください。シェルの内部コマンドを実行していない限り、必要ありませ

于 2009-03-30T11:26:52.677 に答える
5

shell=True を使用してプロセスで terminate を呼び出すと、メモ帳プロセスではなく、実際にはシェルが強制終了されます。シェルは、COMSPEC 環境変数で指定されたものになります。

このメモ帳プロセスを強制終了する唯一の方法は、Win32process.EnumProcesses() を使用してプロセスを検索し、win32api.TerminateProcess を使用して強制終了することです。ただし、メモ帳プロセスを同じ名前の他のプロセスと区別することはできません。

于 2009-03-30T08:46:54.420 に答える
2

Thomas Watnedal の回答で与えられたヒントに基づいて、例ではシェルだけが実際に殺されていることを指摘し、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)
于 2009-03-30T19:35:58.243 に答える
1

フラグが本当に必要な場合は、シェル コマンドをフラグとともにshell=True使用することで解決できます。このフラグを使用すると、プロセスはその子プロセスが終了するまで待機します。次に、たとえばモジュールを使用して、次のシーケンスで目的を達成できます。start/WAITstartpsutil

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

3 行目以降にメモ帳が表示されます。フラグのおかげでウィンドウが開いている限りpoll戻ります。killの子メモ帳ウィンドウが消えた後、終了コードを返します。None/WAITstartpoll

于 2013-12-29T10:18:28.197 に答える
-1

Python 2.6 には、subprocess.Popen オブジェクトの kill メソッドがあります。

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

于 2009-03-30T10:16:37.277 に答える