Python
subprocess
subprocess.run
output suppression
programming

How to suppress or capture the output of subprocess.run?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Python's subprocess module lets you launch external processes and interact with their input, output, and error streams. The subprocess.run() function, introduced in Python 3.5, is the recommended high-level interface for running shell commands from Python code. A very common need is to either capture the output of a command for further processing or suppress it entirely so it does not clutter the terminal. This article walks you through both techniques with clear, practical examples.

How subprocess.run() Works by Default

When you call subprocess.run() without any output-related arguments, the child process inherits the parent's standard output and standard error streams. That means everything the command prints will appear directly in your terminal.

python
1import subprocess
2
3result = subprocess.run(["echo", "Hello, world!"])
4# "Hello, world!" is printed to the terminal automatically
5print(result.returncode)  # 0

The returned CompletedProcess object has stdout and stderr attributes, but both are None unless you explicitly ask Python to capture them.

Capturing Output with capture_output

The simplest way to capture both stdout and stderr is to pass capture_output=True. This tells Python to collect the output into the CompletedProcess object instead of sending it to the terminal.

python
1import subprocess
2
3result = subprocess.run(
4    ["ls", "-la", "/tmp"],
5    capture_output=True,
6    text=True  # decode bytes to str
7)
8
9print(result.stdout)   # the directory listing as a string
10print(result.stderr)   # any error messages as a string

The text=True parameter (also available as universal_newlines=True in older versions) decodes the raw bytes into strings using the system's default encoding. Without it, result.stdout and result.stderr are bytes objects.

Capturing Output with subprocess.PIPE

Under the hood, capture_output=True is shorthand for setting both stdout and stderr to subprocess.PIPE. Using PIPE directly gives you more granular control. For example, you can capture stdout while still letting stderr print to the terminal.

python
1import subprocess
2
3# Capture stdout only; stderr still goes to the terminal
4result = subprocess.run(
5    ["python3", "-c", "import sys; print('out'); print('err', file=sys.stderr)"],
6    stdout=subprocess.PIPE,
7    text=True
8)
9
10print("Captured:", result.stdout.strip())  # "out"
11# "err" was already printed to the terminal by the child process

You can also merge stderr into stdout by redirecting it with stderr=subprocess.STDOUT.

python
1import subprocess
2
3result = subprocess.run(
4    ["python3", "-c", "import sys; print('out'); print('err', file=sys.stderr)"],
5    stdout=subprocess.PIPE,
6    stderr=subprocess.STDOUT,
7    text=True
8)
9
10print(result.stdout)  # contains both "out" and "err"

Suppressing Output Entirely

Sometimes you do not care about the output at all and just want the command to run silently. The cleanest approach is to redirect both streams to subprocess.DEVNULL, which discards everything.

python
1import subprocess
2
3result = subprocess.run(
4    ["ping", "-c", "1", "example.com"],
5    stdout=subprocess.DEVNULL,
6    stderr=subprocess.DEVNULL
7)
8
9print(result.returncode)  # 0 if the host is reachable

This is the equivalent of appending > /dev/null 2>&1 to a shell command. The output is never stored in memory, so this is also the most memory-efficient option when dealing with commands that produce large amounts of output.

Checking for Errors While Capturing

When you capture output, you often want to know if the command failed. Pass check=True to make subprocess.run() raise a CalledProcessError if the return code is non-zero.

python
1import subprocess
2
3try:
4    result = subprocess.run(
5        ["ls", "/nonexistent"],
6        capture_output=True,
7        text=True,
8        check=True
9    )
10except subprocess.CalledProcessError as e:
11    print(f"Command failed with code {e.returncode}")
12    print(f"stderr: {e.stderr}")

The exception object carries stdout, stderr, and returncode, so you can inspect exactly what went wrong.

Common Pitfalls

  • Forgetting text=True: Without this flag, stdout and stderr are raw bytes, which can cause confusing TypeError exceptions when you try to concatenate or print them alongside regular strings.
  • Using capture_output with explicit stdout/stderr: Passing capture_output=True together with stdout= or stderr= raises a ValueError because the two approaches conflict.
  • Deadlocks with large output and PIPE: If you use Popen manually (instead of run) and read only one stream, the other stream's buffer can fill up and block the child process. subprocess.run() handles this for you via internal threading, but it is good to be aware of if you drop down to Popen.
  • Ignoring stderr: Capturing only stdout means error messages still print to the terminal, which can look like your own program's errors to the user. Decide explicitly what to do with stderr.
  • Shell injection risks: Passing shell=True with unsanitized input opens you up to shell injection attacks. Prefer passing the command as a list of arguments whenever possible.

Summary

  • Use capture_output=True, text=True for the simplest way to collect both stdout and stderr as strings.
  • Use stdout=subprocess.PIPE or stderr=subprocess.PIPE individually when you need granular control over which streams to capture.
  • Use stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL to silently discard all output.
  • Combine stderr=subprocess.STDOUT with stdout=subprocess.PIPE to merge both streams into a single captured string.
  • Always consider adding check=True so failures are raised as exceptions rather than silently ignored.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.