Run an external program or command from Python
Use subprocess.run to pass arguments, capture output, check failures, set timeouts, and redirect command output without unnecessary shell parsing.
Use subprocess.run() for a command that should finish before Python continues. Pass the executable and its arguments as a list. This avoids shell interpretation by default and makes spaces in arguments easier to handle.
Run a command
On a Unix-like system:
import subprocess
subprocess.run(["ls", "-la"], check=True)
For a portable example that launches the same Python interpreter:
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-c", "print('child process ready')"],
capture_output=True,
text=True,
check=True,
timeout=10,
)
print(result.stdout.strip())
print(result.returncode)
stdout and stderr are captured separately. text=True decodes them to strings; specify encoding when the command's output encoding is known. A nonzero status raises CalledProcessError with check=True; otherwise inspect returncode yourself.
Why prefer this to os.system()?
os.system("ls -la") runs a shell command and returns an exit-status value. It does not directly return the command's captured output, and its return-value conventions vary by platform. It remains available, but subprocess offers clearer control over streams and failures.
Keep shell syntax out of user input
Do not interpolate an untrusted filename into a string executed with shell=True. On Unix systems, an argument-list example is:
subprocess.run(["cat", "--", filename], check=True)
Here filename must be a validated path from your application. The -- also prevents a leading hyphen from being treated as a cat option. Argument lists prevent shell expansion, not unsafe behavior implemented by the target program. Windows batch files have additional shell-parsing considerations; consult the subprocess security notes before passing untrusted arguments to them.
Redirect output and handle pipelines
import subprocess
import sys
with open("command-output.txt", "w", encoding="utf-8") as output:
subprocess.run(
[sys.executable, "-c", "print('saved output')"],
stdout=output,
check=True,
)
For a small pipeline, capture the first result and pass it to the next command with input=. For large streams, connect Popen pipes, close unused pipe ends, and drain output correctly to avoid deadlocks. Use a shell only when its expansion or control syntax is actually required.
FAQ
Does run block? Yes. timeout= bounds the wait, subject to process-creation limitations, and raises TimeoutExpired. Popen supports more detailed process control; asyncio also provides subprocess APIs.
Is the code portable? The Python interface is portable across supported desktop/server platforms. Executables such as ls and cat, their options, and default shell behavior are not identical across operating systems.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan