How to terminate a python subprocess launched with shellTrue
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When you launch a subprocess with shell=True, Python starts a shell process (/bin/sh on Unix, cmd.exe on Windows), which then spawns your actual command as a child. Calling process.terminate() or process.kill() only kills the shell, not the child command. To kill both, you need to kill the entire process group using os.killpg(), or avoid shell=True altogether and pass the command as a list.
The Problem
proc.pid is the PID of the shell, not the sleep command. Terminating the shell leaves the child as an orphan process.
Fix 1: Kill the Process Group (Recommended)
Start the subprocess as a process group leader and kill the entire group:
os.setsid makes the shell process the leader of a new session/process group. os.killpg() sends the signal to every process in that group, including the child command.
For SIGKILL (force kill):
Fix 2: Avoid shell=True
The simplest and safest approach — pass the command as a list:
Without shell=True, proc.pid is the PID of the actual command, and terminate() works as expected.
When you need shell features (pipes, wildcards, variable expansion), use Python equivalents:
Fix 3: Using subprocess.run with timeout
subprocess.run() with timeout handles cleanup automatically:
However, subprocess.run with shell=True and timeout may still leave orphan children. Combine with preexec_fn=os.setsid and a custom handler for reliable cleanup.
Fix 4: Using psutil for Cross-Platform Process Tree Kill
The psutil library can kill an entire process tree:
This works on both Unix and Windows.
Fix 5: Using start_new_session (Python 3.2+)
Instead of preexec_fn=os.setsid, use the start_new_session parameter:
start_new_session=True is the recommended replacement for preexec_fn=os.setsid — it is safer because preexec_fn is not compatible with threads.
Windows Considerations
On Windows, process groups work differently:
On Windows, os.killpg and os.setsid are not available. Use CREATE_NEW_PROCESS_GROUP and CTRL_BREAK_EVENT instead.
Common Pitfalls
- Calling
terminate()on a shell=True process: This only kills the shell (/bin/sh), leaving the actual command running as an orphan. Always useos.killpg()withstart_new_session=True, or avoidshell=True. - Using
preexec_fn=os.setsidin threaded code:preexec_fnruns betweenfork()andexec(), which is not safe in multi-threaded programs. Usestart_new_session=Trueinstead (Python 3.2+). - Forgetting to call
proc.wait()after kill: Withoutwait(), the process becomes a zombie on Unix. Always callproc.wait()(orproc.communicate()) after sending a kill signal. - Security risks of shell=True: Passing user input in a
shell=Truecommand enables shell injection attacks.Popen(f"grep {user_input} file.txt", shell=True)allows arbitrary command execution. Use list form:Popen(["grep", user_input, "file.txt"]). - SIGTERM vs SIGKILL:
SIGTERMallows the process to clean up (close files, release resources).SIGKILLterminates immediately with no cleanup. TrySIGTERMfirst, thenSIGKILLafter a timeout if the process does not exit.
Summary
shell=Truecreates a shell parent process —terminate()kills the shell but not its child- Use
start_new_session=Trueandos.killpg()to kill the entire process group - Best approach: avoid
shell=Trueand pass commands as a list (["cmd", "arg1", "arg2"]) - Use
psutilfor cross-platform process tree management - On Windows, use
CREATE_NEW_PROCESS_GROUPandCTRL_BREAK_EVENT - Always call
proc.wait()after killing a process to prevent zombies
Related reading
- How to test if a dictionary contains a specific key?
- How to test if a string contains one of the substrings in a list, in pandas?
- How to test NoneType in python?
- How to test single file under pytest
- How to train an SVM classifier on a satellite image using Python
- How to transform items using sklearn Pipeline?
- How to trigger message send of Fastapi websocket outside of Fastapi app
- How to truncate the time on a datetime object?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.