Use subprocess.run() with stdout=subprocess.PIPE and leave stderr unset to capture stdout without redirecting stderr. If you need both streams afterward, use capture_output=True: it captures stdout and stderr separately rather than combining them. Stream arguments, run() reference
Capture stdout while leaving stderr inherited
Replace this example command with your program and its arguments:
import subprocess
command = ["your-tool", "--export"]
result = subprocess.run(
command,
stdout=subprocess.PIPE,
text=True,
check=True,
)
output = result.stdout
Each stream has a different destination:
- stdout goes into a pipe.
- stderr remains inherited because its argument is left at the default,
None.
The inherited stderr destination is not necessarily a terminal; it may already be redirected elsewhere. The important distinction is that the child’s stderr does not enter the stdout capture pipe. Stream arguments
After a successful call, result.stdout contains the captured output. Because stderr was not captured, result.stderr is None. CompletedProcess reference
Use this pattern when your program needs to parse stdout while leaving messages written to stderr at their existing destination. These settings route streams, not message types: anything the command writes to stdout still belongs to captured stdout.
Capture both streams for later inspection
When your application also needs access to stderr, capture both streams. Using the same command:
result = subprocess.run(
command,
capture_output=True,
text=True,
check=True,
)
output = result.stdout
diagnostics = result.stderr
For stream routing, capture_output=True is equivalent to setting both stdout=subprocess.PIPE and stderr=subprocess.PIPE. Do not supply stdout or stderr arguments alongside capture_output=True.
run() waits for the command to finish. In this example, captured stderr becomes available to your code afterward rather than being displayed as it arrives. run() reference
After a successful call, the two streams are available separately as result.stdout and result.stderr. CompletedProcess reference
Avoid merging or discarding stderr
Two other settings serve different purposes:
stderr=subprocess.STDOUTmerges stderr into stdout’s destination. If stdout is captured, the capture contains both streams. This defeats stream separation.stderr=subprocess.DEVNULLsends stderr to the null device. It keeps stderr out of stdout, but discards it rather than preserving it for display or inspection.
If you need separate results, configure separate destinations before starting the command rather than trying to classify messages after merging them. Stream arguments
Handle nonzero exit statuses
Stream routing and exit-status handling are separate choices. With check=True, a nonzero exit status raises subprocess.CalledProcessError instead of returning a result. When both streams were captured, the exception provides their contents through exc.stdout and exc.stderr, along with exc.returncode. run() reference, CalledProcessError reference
This example forwards captured stderr to the parent’s sys.stderr before re-raising the exception:
import subprocess
import sys
command = ["your-tool", "--export"]
try:
result = subprocess.run(
command,
capture_output=True,
text=True,
check=True,
)
except subprocess.CalledProcessError as exc:
if exc.stderr:
sys.stderr.write(exc.stderr)
raise
else:
output = result.stdout
With the stdout-only capture pattern, stderr already goes to its inherited destination. In that case, captured stdout is still available as exc.stdout, but exc.stderr is None; there is no captured stderr to forward. Stream arguments, CalledProcessError reference
Choose text or bytes separately from stream routing
Captured output is bytes by default. These examples use text=True to obtain strings using the default text encoding. If the command’s output contract specifies an encoding, set it explicitly—for example, encoding="utf-8" for a command documented to emit UTF-8. run() reference, CompletedProcess reference
Stream routing determines where output goes; text-mode and encoding options determine how captured output is represented.
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗