Executing command line programs from within python
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Python is often used as a glue language, so calling existing command-line tools is a common requirement. The modern way to do this is the subprocess module, which gives you precise control over arguments, output, exit codes, working directory, and environment variables.
Prefer subprocess.run
For most scripts, subprocess.run is the right starting point. It launches a process, waits for it to finish, and returns a CompletedProcess object with the result.
This style is safer than building a shell string because each argument is passed separately. You do not need to worry about quoting spaces in file names or special shell characters.
The most important arguments are:
- '
capture_output=Trueto collect standard output and standard error' - '
text=Trueto work with Python strings instead of raw bytes' - '
check=Trueto raise an exception if the command exits with a non-zero status' - '
cwd=to run the command from a specific directory' - '
env=to override or add environment variables'
Passing Input and Reading Output
Some programs expect input on standard input. subprocess.run can send that input directly:
If you only care about the output, this pattern is concise and easy to test. You can also direct output to files rather than storing it in memory:
That is useful when the command may produce large output.
Running in a Specific Directory or Environment
Many tools behave differently depending on the working directory or environment variables. subprocess.run lets you control both without changing global process state for the rest of your Python program.
Using cwd is usually better than calling os.chdir before spawning a process because it keeps the scope of the change limited to that child process.
When You Need Popen
subprocess.Popen is lower level and should be used when you need streaming or asynchronous behavior. Examples include long-running programs, interactive tools, or cases where you want to read lines as they arrive.
This is more flexible, but it also creates more ways to make mistakes. Unless you need streaming, stick to subprocess.run.
Should You Use shell=True?
Only use shell=True when you specifically need shell features such as pipes, wildcard expansion, or shell built-ins. Even then, be careful with untrusted input.
If any part of that command string comes from a user, shell=True can become a command injection risk. For normal executables, passing a list of arguments is safer and clearer.
Common Pitfalls
- Using
os.systemfor anything non-trivial gives you less control and weaker error handling thansubprocess. - Forgetting
text=Truemeans output arrives as bytes, which surprises many callers. - Ignoring the exit code can hide command failures until much later in the program.
- Using
shell=Truewith user-provided data creates serious security problems. - Reading huge output with
capture_output=Truecan consume a lot of memory. Stream to a file or usePopenif needed.
Summary
- Use
subprocess.runfor most command execution tasks in Python. - Pass arguments as a list to avoid quoting issues and reduce shell injection risk.
- Use
capture_output,text,cwd, andenvto control how the child process runs. - Reach for
Popenonly when you need streaming or interactive behavior. - Treat
shell=Trueas a special case, not the default.

