`subprocess` — Running External Commands
Python · Standard Library · Run with python3
Explanation
`subprocess.run()` (Python 3.5+) is the recommended way to run shell commands. `capture_output=True` captures stdout/stderr; `text=True` decodes them as strings; `check=True` raises `CalledProcessError` on non-zero exit. `subprocess.Popen` gives full control for interactive processes or streaming output. Never pass `shell=True` with untrusted user input — it creates a shell injection vulnerability.
Real-World Scenario
A build script runs `git log`, `pytest`, and `docker build` as subprocesses. `subprocess.run(["git", "log", "--oneline", "-10"], capture_output=True, text=True, check=True)` captures the last 10 commits without a shell and raises an exception if git fails. ```python import subprocess import sys def run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess: return subprocess.run(cmd, capture_output=True, text=True, check=True, **kwargs) # Get Python version result = run([sys.executable, "--version"]) print(result.stdout.strip() or result.stderr.strip()) # List files (cross-platform) import os if os.name == "nt": result = run(["cmd", "/c", "dir", "/b"]) else: result = run(["ls", "-la"]) print(result.stdout[:200]) # Handle failure gracefully try: run(["false"]) # Unix command that always exits 1 except subprocess.CalledProcessError as e: print(f"Command failed with exit code {e.returncode}") except FileNotFoundError: print("Command not found (Windows: skipping 'false')") ```
Quick Snippet
import subprocess
import sys
def run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess:
return subprocess.run(cmd, capture_output=True, text=True, check=True, **kwargs)
# Get Python version
result = run([sys.executable, "--version"])
print(result.stdout.strip() or result.stderr.strip())
# List files (cross-platform)
import os
if os.name == "nt":
result = run(["cmd", "/c", "dir", "/b"])
else:
result = run(["ls", "-la"])
print(result.stdout[:200])
# Handle failure gracefully
try:
run(["false"]) # Unix command that always exits 1
except subprocess.CalledProcessError as e:
print(f"Command failed with exit code {e.returncode}")
except FileNotFoundError:
print("Command not found (Windows: skipping 'false')")Full Example
# Compile: python3 subprocess_basics.py
# Output:
# Python version printed
import subprocess
import sys
def run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess:
return subprocess.run(cmd, capture_output=True, text=True, check=True, **kwargs)
result = run([sys.executable, "--version"])
version = result.stdout.strip() or result.stderr.strip()
print(version)
# List files in current directory
import os
if os.name == "nt":
result = subprocess.run(
["cmd", "/c", "dir", "/b"],
capture_output=True, text=True
)
else:
result = subprocess.run(
["ls"],
capture_output=True, text=True
)
lines = result.stdout.strip().splitlines()
print(f"Found {len(lines)} entries")
# Handle failure gracefully
try:
subprocess.run(
[sys.executable, "-c", "import sys; sys.exit(1)"],
check=True
)
except subprocess.CalledProcessError as e:
print(f"Command failed with exit code {e.returncode}")
python3 subprocess_basics.py