snippetpythonModeratepending
Python subprocess best practices
Viewed 0 times
subprocessrunpopenshellcapture outputtimeout
Problem
Need to run external commands from Python safely, capturing output and handling errors.
Solution
Modern subprocess patterns:
import subprocess
# Basic: run and check result
result = subprocess.run(
['git', 'status', '--porcelain'],
capture_output=True,
text=True,
check=True, # Raises CalledProcessError on non-zero exit
)
print(result.stdout)
# With timeout
try:
result = subprocess.run(
['long-running-command'],
capture_output=True, text=True,
timeout=30, # seconds
)
except subprocess.TimeoutExpired:
print('Command timed out')
# Pipe between commands (instead of shell=True)
ps = subprocess.run(['ps', 'aux'], capture_output=True)
result = subprocess.run(
['grep', 'python'],
input=ps.stdout,
capture_output=True, text=False
)
# NEVER do this (shell injection risk):
# subprocess.run(f'ls {user_input}', shell=True) # DANGEROUS!
# Safe alternative with user input:
subprocess.run(['ls', user_input]) # Each arg is escaped
# Stream output in real-time
with subprocess.Popen(
['tail', '-f', '/var/log/app.log'],
stdout=subprocess.PIPE,
text=True,
) as proc:
for line in proc.stdout:
print(f'LOG: {line}', end='')
# Set environment and working directory
result = subprocess.run(
['make', 'build'],
env={**os.environ, 'DEBUG': '1'},
cwd='/path/to/project',
capture_output=True, text=True,
)Why
subprocess.run() with a list of arguments prevents shell injection. shell=True should almost never be used with user-provided input.
Gotchas
- shell=True with user input = command injection vulnerability
- capture_output=True is equivalent to stdout=PIPE, stderr=PIPE
- check=True raises on non-zero exit - handle CalledProcessError
Context
Python scripts that need to run external commands
Revisions (0)
No revisions yet.