Je lance un sous-processus avec la commande suivante:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, Shell=True)
Cependant, quand j'essaye de tuer en utilisant:
p.terminate()
ou
p.kill()
La commande continue de fonctionner en arrière-plan, je me demandais donc comment puis-je terminer le processus.
Notez que lorsque je lance la commande avec:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
Il se termine avec succès lors de l'émission de la p.terminate()
.
Utilisez un groupe de processus afin d'activer l'envoi d'un signal à tous les processus des groupes. Pour cela, vous devez associer un ID de session au processus parent du processus engendré/enfant, qui est un shell dans votre cas. Cela en fera le chef de groupe des processus. Alors maintenant, lorsqu'un signal est envoyé au responsable du groupe de processus, il est transmis à tous les processus enfants de ce groupe.
Voici le 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()
finit par tuer le processus Shell et cmd
est toujours en cours d'exécution.
J'ai trouvé une solution pratique par:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, Shell=True)
Cela fera en sorte que cmd hérite du processus Shell au lieu que celui-ci lance un processus enfant qui ne soit pas tué. p.pid
sera alors l'id de votre processus cmd.
p.kill()
devrait fonctionner.
Je ne sais pas quel effet cela aura sur votre pipe si.
Si vous pouvez utiliser psutil , cela fonctionnera parfaitement:
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)
Je pourrais le faire en utilisant
from subprocess import Popen
process = Popen(command, Shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
il a tué le cmd.exe
et le programme que j'ai donné à la commande.
(Sous Windows)
Lorsque Shell=True
, le shell est le processus enfant et les commandes sont ses enfants. Donc, toute SIGTERM
ou SIGKILL
va tuer Shell mais pas ses processus enfants, et je ne me souviens pas du meilleur moyen de le faire . Le meilleur moyen auquel je puisse penser est d'utiliser Shell=False
, sinon, lorsque vous supprimez le processus Shell parent, il laissera un processus Shell obsolète.
Aucune de ces réponses n'a fonctionné pour moi alors je laisse le code qui a fonctionné. Dans mon cas, même après avoir arrêté le processus avec .kill()
et obtenu un code de retour .poll()
, le processus ne s'est pas terminé.
En suivant le subprocess.Popen
documentation :
"... afin de nettoyer correctement une application bien conçue devrait tuer le processus enfant et terminer la communication ..."
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
Dans mon cas, il me manquait la proc.communicate()
après avoir appelé proc.kill()
. Cela nettoie le processus stdin, stdout ... et met fin au processus.
Comme Sai l'a dit, Shell est l'enfant, ainsi les signaux sont interceptés. Le meilleur moyen que j'ai trouvé est d'utiliser Shell = False et d'utiliser shlex pour fractionner la ligne de commande:
if isinstance(command, unicode):
cmd = command.encode('utf8')
args = shlex.split(cmd)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Ensuite, p.kill () et p.terminate () devraient fonctionner comme vous le souhaitez.
ce que je sens que nous pourrions utiliser:
import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, Shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
cela ne tuera pas toute votre tâche mais le processus avec le p.pid
Je n'ai pas vu cela mentionné ici, alors je le publie au cas où quelqu'un en aurait besoin. Si vous souhaitez simplement vous assurer que votre sous-processus se termine correctement, vous pouvez le placer dans un gestionnaire de contexte. Par exemple, je voulais que mon imprimante standard imprime une image externe et, à l'aide du gestionnaire de contexte, m'assurais que le sous-processus se terminait.
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...')
Je crois que cette méthode est également multi-plateforme.
Je sais que c'est une vieille question, mais cela peut aider quelqu'un à la recherche d'une méthode différente. C’est ce que j’utilise sous Windows pour supprimer les processus que j’ai appelés.
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)
/ IM est le nom de l'image, vous pouvez aussi faire/PID si vous le souhaitez./T tue le processus ainsi que les processus enfants./F force le termine. Si, comme je l'ai défini, voici comment procéder: sans afficher de fenêtre CMD. Ce code est utilisé dans Python 3.
Envoyer le signal à tous les processus du groupe
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)