How to terminate a python subprocess launched with shell=True
Use a process group so as to enable sending a signal to all the process in the groups. For that, you should attach a session id to the parent process of the spawned/child processes, which is a shell in your case. This will make it the group leader of the processes. So now, when a signal is sent to the process group leader, it's transmitted to all of the child processes of this group.
Here's the code:
import osimport signalimport 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() ends up killing the shell process and
cmd is still running.
I found a convenient fix this by:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
This will cause cmd to inherit the shell process, instead of having the shell launch a child process, which does not get killed.
p.pid will be the id of your cmd process then.
p.kill() should work.
I don't know what effect this will have on your pipe though.
If you can use psutil, then this works perfectly:
import subprocessimport psutildef 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)