Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

Running External Programs with subprocess

Run child processes safely with argument lists, captured streams, exit-code handling, and timeouts using Python's subprocess module.

Levels: Intermediate ~24 min read

Intermediate

Sometimes a Python program needs to run another program and use its result. The subprocess module starts a child process and lets your Python code inspect its output and exit status. For the common case, the official documentation recommends subprocess.run(); use the lower-level Popen interface only when you need more control over a process while it is running.

Start with subprocess.run()

Pass the command as a sequence of arguments. sys.executable selects the Python interpreter running this example, so the child does not depend on a platform-specific command name. capture_output=True collects standard output and standard error, text=True decodes captured streams to strings, and check=True raises an exception if the child exits unsuccessfully.

Interactive Runnable example
Edit

Ready to run.

Keep arguments separate and avoid the shell

With the default shell=False, subprocess passes each sequence item as a separate argument rather than asking a shell to interpret it. Spaces, dollar signs, and semicolons inside an argument remain ordinary characters. Do not build a shell command by concatenating user input; shell=True introduces shell parsing and can create command-injection vulnerabilities. One platform caveat matters: Windows may route .bat or .cmd files through a system shell even when shell=False, so do not treat that setting as protection for untrusted arguments to batch files.

Interactive Runnable example
Edit

Ready to run.

Send input and capture output

Use input= to send data to the child's standard input. With text=True, supply and receive strings. capture_output=True collects both stdout and stderr; choose stdout=PIPE and stderr=PIPE individually only when you need to configure them separately. The streams may be empty, and stderr is not the same as a Python exception.

Interactive Runnable example
Edit

Ready to run.

Choose how to handle a nonzero exit

A completed process has a returncode. Zero conventionally indicates success, but your program must interpret the child's documented contract. With check=False, inspect returncode and captured stderr yourself. With check=True, a nonzero status raises subprocess.CalledProcessError, which exposes the return code and captured output when available.

Interactive Runnable example
Edit

Ready to run.

Set a time limit and know what remains deferred

A timeout prevents run() from waiting indefinitely: when the limit expires, subprocess.TimeoutExpired is raised after the child is terminated and waited for. A timeout is not a complete sandbox and does not make an unsafe command safe. This lesson focuses on run(); streaming large amounts of data, interacting with a long-running process, process groups, and low-level Popen lifecycle control need a separate, more advanced treatment. Process creation itself may take longer than the requested limit on some operating systems, so timeout is not a strict real-time guarantee.

Interactive Runnable example
Edit

Ready to run.

Quick Check

Quick check

Which approach should be the default for launching a known program with separate arguments?

import subprocess
import sys

result = subprocess.run(
    [sys.executable, "-c", "print('safe')"],
    capture_output=True, text=True, check=True, timeout=5
)
print(result.stdout.strip())

Quick check

What does capture_output=True do when subprocess.run() completes?

import subprocess, sys
result = subprocess.run([sys.executable, "-c", "print('out'); print('err', file=__import__('sys').stderr)"], capture_output=True, text=True, timeout=5)
print(result.stdout.strip(), result.stderr.strip())

Quick check

Which exception does check=True raise when the child returns a nonzero status?

import subprocess, sys
try:
    subprocess.run([sys.executable, "-c", "raise SystemExit(3)"], check=True, timeout=5)
except subprocess.CalledProcessError as error:
    print(error.returncode)

Quick check

What is the effect of timeout=1 for a child process that does not finish in time?

import subprocess, sys
try:
    subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=0.05)
except subprocess.TimeoutExpired:
    print('stopped waiting')

Quick check

Why is shell=True usually inappropriate when arguments include untrusted input?

import subprocess, sys
value = "semi;colon $HOME"
result = subprocess.run([sys.executable, "-c", "import sys; print(sys.argv[1])", value], capture_output=True, text=True, check=True, timeout=5)
print(result.stdout.strip())
Was this page helpful?

Mark this learning resource complete to track your learning progress.