How to terminate a python subprocess launched with shell=True How to terminate a python subprocess launched with shell=True python python

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)