Python
subprocess
programming
Popen
output-handling

Store output of subprocess.Popen call in a string

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

If you want the output of a subprocess.Popen call as a Python string, the usual pattern is to capture stdout with PIPE and then call communicate(). The important detail is to decide whether you want bytes or decoded text, because Popen can give you either depending on how you configure it.

Basic Popen Pattern

Here is the classic approach:

python
1import subprocess
2
3process = subprocess.Popen(
4    ["echo", "hello"],
5    stdout=subprocess.PIPE,
6    stderr=subprocess.PIPE,
7    text=True,
8)
9
10stdout, stderr = process.communicate()
11print(stdout)

With text=True, the returned values are strings rather than raw bytes. Without it, you would need to decode manually.

If You Omit text=True, Decode the Bytes

python
1import subprocess
2
3process = subprocess.Popen(
4    ["echo", "hello"],
5    stdout=subprocess.PIPE,
6)
7
8stdout, _ = process.communicate()
9output = stdout.decode("utf-8")
10print(output)

Both approaches work. Using text=True is usually cleaner in modern Python unless you specifically want bytes.

Why communicate() Matters

communicate() is the safe way to collect subprocess output because it waits for the process to finish and reads the pipes correctly. Reading directly from stdout in ad hoc ways can lead to hangs or incomplete output if the process also writes to stderr or produces more data than expected.

That is why communicate() is the standard answer instead of hand-rolled pipe reading for simple cases.

Capture Both Output Streams When Debugging

If the command might fail, capturing only stdout can hide the real reason.

python
1process = subprocess.Popen(
2    ["python", "--bad-flag"],
3    stdout=subprocess.PIPE,
4    stderr=subprocess.PIPE,
5    text=True,
6)
7
8stdout, stderr = process.communicate()
9print("stdout:", stdout)
10print("stderr:", stderr)
11print("return code:", process.returncode)

For scripts and tooling, the return code plus stderr are often as important as the main output string.

Consider subprocess.run for Simpler Cases

If you only want the final captured output and do not need the full flexibility of Popen, subprocess.run is often easier.

python
1result = subprocess.run(
2    ["echo", "hello"],
3    capture_output=True,
4    text=True,
5    check=True,
6)
7
8output = result.stdout

The article topic may mention Popen, but the better modern API for many one-shot commands is run.

Keep Shell Usage Deliberate

If you use shell=True, the command string is interpreted by the shell rather than executed directly as a program argument list. That can be convenient for shell syntax, but it also changes quoting rules and increases security risk when user input is involved. For ordinary command execution, passing a list of arguments is usually safer and simpler.

Large Outputs May Need a Different Strategy

Capturing all output into one string is fine for moderate command output, but very large outputs can consume a lot of memory. In those cases, streaming line by line or redirecting to a file may be more appropriate than buffering everything into one in-memory string.

Common Pitfalls

  • Forgetting stdout=subprocess.PIPE and then wondering why nothing was captured.
  • Decoding manually even though text=True would return strings directly.
  • Ignoring stderr and missing the actual failure message.
  • Reading pipes unsafely instead of using communicate().
  • Reaching for Popen when subprocess.run would express the task more simply.

Summary

  • To store Popen output in a string, capture stdout and call communicate().
  • Use text=True for direct string output or decode the bytes yourself.
  • Capture stderr too when command failure details matter.
  • communicate() is safer than ad hoc pipe reading for ordinary cases.
  • For one-shot subprocess execution, subprocess.run is often the simpler modern choice.
  • Captured output should be paired with the return code when correctness really matters.
  • Small diagnostics save debugging time later.

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.