Ich starte einen Subprozess mit dem folgenden Befehl:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, Shell=True)
Jedoch wenn ich versuche zu töten mit:
p.terminate()
oder
p.kill()
Der Befehl läuft im Hintergrund weiter, also habe ich mich gefragt, wie ich den Vorgang eigentlich beenden kann.
Beachten Sie Folgendes, wenn ich den Befehl mit:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
Es wird erfolgreich beendet, wenn p.terminate()
ausgegeben wird.
Verwenden Sie eine Prozessgruppe , um das Senden eines Signals an alle Prozesse in den Gruppen zu ermöglichen. Dazu müssen Sie eine session id an den übergeordneten Prozess der erzeugten/untergeordneten Prozesse anhängen, was in Ihrem Fall eine Shell ist. Dies macht es zum Gruppenleiter der Prozesse. Wenn nun ein Signal an den Prozessgruppenleiter gesendet wird, wird es an alle Kindprozesse dieser Gruppe übertragen.
Hier ist der Code:
import os
import signal
import subprocess
# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before exec() to run the Shell.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE,
Shell=True, preexec_fn=os.setsid)
os.killpg(os.getpgid(pro.pid), signal.SIGTERM) # Send the signal to all the process groups
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, Shell=True)
p.kill()
p.kill()
beendet den Shell-Prozess und cmd
läuft noch.
Ich habe eine bequeme Lösung gefunden durch:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, Shell=True)
Dies führt dazu, dass cmd den Shell-Prozess erbt, anstatt dass die Shell einen untergeordneten Prozess startet, der nicht beendet wird. p.pid
ist dann die ID Ihres cmd-Prozesses.
p.kill()
sollte funktionieren.
Ich weiß nicht, welche Auswirkungen dies auf Ihre Pfeife haben wird.
Wenn Sie psutil verwenden können, funktioniert das perfekt:
import subprocess
import psutil
def kill(proc_pid):
process = psutil.Process(proc_pid)
for proc in process.children(recursive=True):
proc.kill()
process.kill()
proc = subprocess.Popen(["infinite_app", "param"], Shell=True)
try:
proc.wait(timeout=3)
except subprocess.TimeoutExpired:
kill(proc.pid)
Ich könnte es mit machen
from subprocess import Popen
process = Popen(command, Shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
es tötete den cmd.exe
und das Programm, für das ich den Befehl gab.
(Unter Windows)
Wenn Shell=True
die Shell der untergeordnete Prozess ist und die Befehle ihre untergeordneten sind. Also SIGTERM
oder SIGKILL
töten die Shell, aber nicht ihre untergeordneten Prozesse, und ich erinnere mich nicht an eine gute Vorgehensweise. Der beste Weg, den ich mir vorstellen kann, ist, Shell=False
zu verwenden. Andernfalls wird der übergeordnete Shell-Prozess abgebrochen.
Keine dieser Antworten hat für mich funktioniert, also lasse ich den Code, der funktioniert hat. In meinem Fall, selbst nachdem der Prozess mit .kill()
beendet und ein .poll()
-Rückkehrcode erhalten wurde, wurde der Prozess nicht beendet.
Nach der subprocess.Popen
Dokumentation :
"... um eine ordnungsgemäße Bereinigung durchzuführen, sollte der untergeordnete Prozess abgebrochen und die Kommunikation beendet werden ..."
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
In meinem Fall fehlte mir nach dem Aufruf von proc.communicate()
die proc.kill()
. Dies reinigt den Prozess stdin, stdout ... und beendet den Prozess.
Wie Sai gesagt hat, ist die Shell das Kind, also werden Signale von ihr abgefangen - die beste Methode, die ich gefunden habe, ist die Verwendung von Shell = False und die Aufteilung der Befehlszeile mit shlex:
if isinstance(command, unicode):
cmd = command.encode('utf8')
args = shlex.split(cmd)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Dann sollten p.kill () und p.terminate () so funktionieren, wie Sie es erwarten.
was ich fühle, wir könnten verwenden:
import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, Shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
dies wird nicht alle Ihre Aufgabe beenden, sondern den Prozess mit der p.pid
Ich habe das hier nicht gesehen, also stelle ich es da raus, falls jemand es braucht. Wenn Sie nur sicherstellen möchten, dass Ihr Unterprozess erfolgreich beendet wird, können Sie ihn in einen Kontextmanager einfügen. Ich wollte zum Beispiel, dass mein Standarddrucker ein Bild druckt und über den Kontextmanager sicherstellt, dass der Unterprozess beendet wird.
import subprocess
with open(filename,'rb') as f:
img=f.read()
with subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE) as lpr:
lpr.stdin.write(img)
print('Printed image...')
Ich glaube, diese Methode ist auch plattformübergreifend.
Ich weiß, dass dies eine alte Frage ist, aber dies kann jemandem helfen, der nach einer anderen Methode sucht. Dies ist, was ich unter Windows benutze, um Prozesse zu beenden, die ich aufgerufen habe.
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)
/ IM ist der Bildname. Sie können auch/PID verwenden, wenn Sie möchten./T beendet den Prozess sowie die Kindprozesse./F Kraft beendet es. si, wie ich es eingestellt habe, ist, wie Sie dies tun, ohne ein CMD-Fenster anzuzeigen. Dieser Code wird in Python 3 verwendet.
Senden Sie das Signal an alle Prozesse in der Gruppe
self.proc = Popen(commands,
stdout=PIPE,
stderr=STDOUT,
universal_newlines=True,
preexec_fn=os.setsid)
os.killpg(os.getpgid(self.proc.pid), signal.SIGHUP)
os.killpg(os.getpgid(self.proc.pid), signal.SIGTERM)