subprocess

Updated March 13, 2026 · Modules
stdlib process subprocess shell

The subprocess module provides functions for spawning new processes, running shell commands, and managing their input/output streams. It is the standard way to execute external commands in Python, replacing older modules like os.system() and os.popen(). The module gives you full control over stdin, stdout, stderr, and the process lifecycle.

Syntax

import subprocess

Functions

run()

Executes a command and waits for it to complete. Returns a CompletedProcess object containing the return code and output.

subprocess.run(args, *, stdin=None, input=None, capture_output=False, timeout=None, check=False, cwd=None, env=None, ...)
ParameterTypeDefaultDescription
argsstr or listCommand to execute, either as string (shell=True) or list of arguments
stdinfile-likeNoneStandard input source: None, PIPE, DEVNULL, or a file object
inputbytes/strNoneData to send to stdin (implies PIPE)
capture_outputboolFalseIf True, capture both stdout and stderr
timeoutfloatNoneSeconds to wait before raising TimeoutExpired
checkboolFalseRaise CalledProcessError if return code is non-zero
cwdstrNoneWorking directory for the subprocess
envdictNoneEnvironment variables for the subprocess

call()

Runs a command and returns the return code. Simpler than run() but less flexible.

subprocess.call(args, *, stdin=None, shell=False, cwd=None, timeout=None, ...)
ParameterTypeDefaultDescription
argsstr or listCommand to execute
stdinfile-likeNoneStandard input source
shellboolFalseIf True, run command through shell
cwdstrNoneWorking directory
timeoutfloatNoneSeconds to wait

check_output()

Runs a command and returns its output as bytes. Raises CalledProcessError if the return code is non-zero.

subprocess.check_output(args, *, input=None, stderr=None, shell=False, cwd=None, ...)
ParameterTypeDefaultDescription
argsstr or listCommand to execute
inputbytesNoneData to send to stdin
stderrfile-likeNoneWhere to send stderr: None, PIPE, STDOUT, DEVNULL
shellboolFalseRun command through shell
cwdstrNoneWorking directory

Popen

The underlying class for process creation. Provides asynchronous execution and full control over process streams.

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, ...)
ParameterTypeDefaultDescription
argsstr or listCommand to execute
bufsizeint-1Buffer size for I/O operations
executablestrNonePath to executable (replaces args[0])
stdinfile-likeNoneStandard input: PIPE, DEVNULL, or file
stdoutfile-likeNoneStandard output: PIPE, DEVNULL, or file
stderrfile-likeNoneStandard error: PIPE, DEVNULL, STDOUT, or file

Popen Methods:

  • communicate() — Send input and read output
  • wait() — Wait for process to terminate
  • poll() — Check if process has finished
  • terminate() — Kill the process
  • kill() — Kill the process with SIGKILL

Examples

Basic usage with run()

import subprocess

result = subprocess.run(["echo", "Hello from subprocess"])
print(result.returncode)
# 0

Capturing output

import subprocess

# Capture stdout and stderr
result = subprocess.run(
    ["python", "--version"],
    capture_output=True,
    text=True
)
print(result.stdout)
# Python 3.12.0

print(result.stderr)
# (empty)

Using check_output()

import subprocess

output = subprocess.check_output(["ls", "-la"], text=True)
print(output[:200])
# total 64
# drwxr-xr-x  5 user  user  4096 Mar  9 14:30 .
# drwxr-xr-x  5 user  user  4096 Mar  9 14:30 ..

Using Popen for streaming I/O

import subprocess

proc = subprocess.Popen(
    ["grep", "python"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)

stdout, stderr = proc.communicate(input="python is great\njava is okay\npython rocks")
print(stdout)
# python is great
# python rocks

Running with shell commands

import subprocess

# Shell expansion works with shell=True
result = subprocess.run(
    "echo Home: $HOME && ls *.py 2>/dev/null | head -3",
    shell=True,
    capture_output=True,
    text=True
)
print(result.stdout)
# Home: /home/user
# main.py
# utils.py

Common Patterns

Capturing command output in one line

import subprocess

# One-liner to get command output
date = subprocess.check_output(["date"]).decode().strip()
print(date)
# Mon Mar  9 14:30:00 UTC 2026

Handling timeouts

import subprocess

try:
    result = subprocess.run(
        ["sleep", "10"],
        timeout=2
    )
except subprocess.TimeoutExpired:
    print("Command timed out")
# Command timed out

Checking return codes

import subprocess

# Using check=True to raise on error
try:
    subprocess.run(
        ["false"],  # exits with code 1
        check=True
    )
except subprocess.CalledProcessError as e:
    print(f"Command failed with code {e.returncode}")
# Command failed with code 1

Passing environment variables

import subprocess

env = {"MY_VAR": "hello"}
result = subprocess.run(
    ["python", "-c", "import os; print(os.environ.get('MY_VAR', 'not found'))"],
    env=env,
    capture_output=True,
    text=True
)
print(result.stdout)
# hello

Errors

ErrorWhen it occurs
FileNotFoundErrorExecutable not found in PATH
TimeoutExpiredProcess exceeds timeout
CalledProcessErrorcheck=True and return code is non-zero
PermissionErrorExecutable lacks execute permission

See Also