Cómo terminar un subproceso de Python iniciado con shell=True
Estoy lanzando un subproceso con el siguiente comando:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
Sin embargo, cuando intento matar usando:
p.terminate()
o
p.kill()
El comando sigue ejecutándose en segundo plano, por lo que me preguntaba cómo puedo finalizar el proceso.
Tenga en cuenta que cuando ejecuto el comando con:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
Termina exitosamente al emitir el archivo p.terminate()
.
Utilice un grupo de procesos para permitir el envío de una señal a todos los procesos de los grupos. Para eso, debe adjuntar una identificación de sesión al proceso principal de los procesos generados/secundarios, que es un shell en su caso. Esto lo convertirá en el líder del grupo de los procesos. Ahora, cuando se envía una señal al líder del grupo de procesos, se transmite a todos los procesos secundarios de este grupo.
Aquí está el código:
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()
termina matando el proceso de shell y cmd
todavía se está ejecutando.
Encontré una solución conveniente para esto:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
Esto hará que cmd herede el proceso del shell, en lugar de que el shell inicie un proceso hijo, que no se elimina. p.pid
Entonces será la identificación de su proceso cmd.
p.kill()
Deberia trabajar.
Aunque no sé qué efecto tendrá esto en tu pipa.
Si puedes usar psutil , entonces esto funciona perfectamente:
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)
podría hacerlo usando
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
Mató el cmd.exe
programa y el programa para el que di el comando.
(En Windows)
Cuando shell=True
el shell es el proceso hijo y los comandos son sus hijos. Entonces cualquiera SIGTERM
o SIGKILL
matará el shell pero no sus procesos secundarios, y no recuerdo una buena manera de hacerlo. La mejor manera que se me ocurre es usar shell=False
; de lo contrario, cuando finalice el proceso de shell principal, dejará un proceso de shell inactivo.