Capturing output

subprocess · Essentials · 8 min

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 what capture_output sets 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 nothing

Remember

  • 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.

Check yourself

  1. Which call merges a command's errors into result.stdout?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess