subprocess
The subprocess module provides functions for spawning new processes, running shell commands, and managing their input/output streams. It is the standard way to execute external commands in Python, replacing older modules like os.system() and os.popen(). The module gives you full control over stdin, stdout, stderr, and the process lifecycle.
Syntax
import subprocess
Functions
run()
Executes a command and waits for it to complete. Returns a CompletedProcess object containing the return code and output.
subprocess.run(args, *, stdin=None, input=None, capture_output=False, timeout=None, check=False, cwd=None, env=None, ...)
| Parameter | Type | Default | Description |
|---|---|---|---|
args | str or list | — | Command to execute, either as string (shell=True) or list of arguments |
stdin | file-like | None | Standard input source: None, PIPE, DEVNULL, or a file object |
input | bytes/str | None | Data to send to stdin (implies PIPE) |
capture_output | bool | False | If True, capture both stdout and stderr |
timeout | float | None | Seconds to wait before raising TimeoutExpired |
check | bool | False | Raise CalledProcessError if return code is non-zero |
cwd | str | None | Working directory for the subprocess |
env | dict | None | Environment variables for the subprocess |
call()
Runs a command and returns the return code. Simpler than run() but less flexible.
subprocess.call(args, *, stdin=None, shell=False, cwd=None, timeout=None, ...)
| Parameter | Type | Default | Description |
|---|---|---|---|
args | str or list | — | Command to execute |
stdin | file-like | None | Standard input source |
shell | bool | False | If True, run command through shell |
cwd | str | None | Working directory |
timeout | float | None | Seconds to wait |
check_output()
Runs a command and returns its output as bytes. Raises CalledProcessError if the return code is non-zero.
subprocess.check_output(args, *, input=None, stderr=None, shell=False, cwd=None, ...)
| Parameter | Type | Default | Description |
|---|---|---|---|
args | str or list | — | Command to execute |
input | bytes | None | Data to send to stdin |
stderr | file-like | None | Where to send stderr: None, PIPE, STDOUT, DEVNULL |
shell | bool | False | Run command through shell |
cwd | str | None | Working directory |
Popen
The underlying class for process creation. Provides asynchronous execution and full control over process streams.
subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, ...)
| Parameter | Type | Default | Description |
|---|---|---|---|
args | str or list | — | Command to execute |
bufsize | int | -1 | Buffer size for I/O operations |
executable | str | None | Path to executable (replaces args[0]) |
stdin | file-like | None | Standard input: PIPE, DEVNULL, or file |
stdout | file-like | None | Standard output: PIPE, DEVNULL, or file |
stderr | file-like | None | Standard error: PIPE, DEVNULL, STDOUT, or file |
Popen Methods:
communicate()— Send input and read outputwait()— Wait for process to terminatepoll()— Check if process has finishedterminate()— Kill the processkill()— Kill the process with SIGKILL
Examples
Basic usage with run()
import subprocess
result = subprocess.run(["echo", "Hello from subprocess"])
print(result.returncode)
# 0
Capturing output
import subprocess
# Capture stdout and stderr
result = subprocess.run(
["python", "--version"],
capture_output=True,
text=True
)
print(result.stdout)
# Python 3.12.0
print(result.stderr)
# (empty)
Using check_output()
import subprocess
output = subprocess.check_output(["ls", "-la"], text=True)
print(output[:200])
# total 64
# drwxr-xr-x 5 user user 4096 Mar 9 14:30 .
# drwxr-xr-x 5 user user 4096 Mar 9 14:30 ..
Using Popen for streaming I/O
import subprocess
proc = subprocess.Popen(
["grep", "python"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = proc.communicate(input="python is great\njava is okay\npython rocks")
print(stdout)
# python is great
# python rocks
Running with shell commands
import subprocess
# Shell expansion works with shell=True
result = subprocess.run(
"echo Home: $HOME && ls *.py 2>/dev/null | head -3",
shell=True,
capture_output=True,
text=True
)
print(result.stdout)
# Home: /home/user
# main.py
# utils.py
Common Patterns
Capturing command output in one line
import subprocess
# One-liner to get command output
date = subprocess.check_output(["date"]).decode().strip()
print(date)
# Mon Mar 9 14:30:00 UTC 2026
Handling timeouts
import subprocess
try:
result = subprocess.run(
["sleep", "10"],
timeout=2
)
except subprocess.TimeoutExpired:
print("Command timed out")
# Command timed out
Checking return codes
import subprocess
# Using check=True to raise on error
try:
subprocess.run(
["false"], # exits with code 1
check=True
)
except subprocess.CalledProcessError as e:
print(f"Command failed with code {e.returncode}")
# Command failed with code 1
Passing environment variables
import subprocess
env = {"MY_VAR": "hello"}
result = subprocess.run(
["python", "-c", "import os; print(os.environ.get('MY_VAR', 'not found'))"],
env=env,
capture_output=True,
text=True
)
print(result.stdout)
# hello
Errors
| Error | When it occurs |
|---|---|
FileNotFoundError | Executable not found in PATH |
TimeoutExpired | Process exceeds timeout |
CalledProcessError | check=True and return code is non-zero |
PermissionError | Executable lacks execute permission |