Most scripts need to use what a command prints, such as a git hash or a JSON listing.
To get the output into Python instead of the terminal, pass capture_output=True. Then result.stdout and result.stderr hold what the program wrote.
By default they are bytes. Add text=True to decode them into str using the locale encoding (normally UTF-8), or pass encoding="utf-8" to be explicit, which also implies text mode. text=True also normalises line endings to \n.
out = subprocess.run(["git", "rev-parse", "HEAD"],
capture_output=True, text=True).stdout.strip()Remember .strip(): command output usually ends with a newline.
Finer control comes from the stdout= and stderr= parameters:
subprocess.PIPE: capture (that's whatcapture_outputsets for both).subprocess.DEVNULL: discard.stderr=subprocess.STDOUT: merge stderr into stdout, preserving interleaving.- An open file object: write straight to a file.
You can't combine capture_output=True with stdout= or stderr=. Captured output is held in memory until the process exits, which is fine for normal commands but not for something that prints gigabytes; stream those with Popen instead.
Example
import subprocess, sys
code = "import sys; print('to out'); print('to err', file=sys.stderr)"
r = subprocess.run([sys.executable, "-c", code], capture_output=True)
print(r.stdout) # b'to out\n'
r = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True)
print(repr(r.stdout), repr(r.stderr)) # 'to out\n' 'to err\n'
r = subprocess.run([sys.executable, "-c", code], text=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print(r.stdout.splitlines()) # ['to out', 'to err']
subprocess.run([sys.executable, "-c", code], stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL) # prints nothingRemember
- capture_output=True fills result.stdout and result.stderr
- text=True (or encoding=) gives str instead of bytes
- PIPE, DEVNULL, STDOUT and file objects route each stream
Watch out for
- Forgetting text=True and then comparing bytes output with a str.