command
system
execute
program

How do I execute a program or call a system command?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In modern Python, the standard way to execute another program or system command is the subprocess module. The main recommendation is to use subprocess.run for straightforward commands and avoid older shortcuts such as os.system unless you specifically need their simpler but less flexible behavior.

Use subprocess.run for Ordinary Commands

For most cases, subprocess.run is the right starting point.

python
1import subprocess
2
3result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
4print(result.stdout)

This runs the command, waits for it to finish, and gives you access to:

  • standard output
  • standard error
  • exit status

Passing the command as a list is safer than passing one shell string because Python does the argument handling directly.

Check for Failures Explicitly

If the command must succeed, use check=True.

python
import subprocess

subprocess.run(["mkdir", "-p", "build"], check=True)

With check=True, Python raises CalledProcessError when the command exits with a nonzero status. That is better than silently continuing after a failed external command.

Capture Output Only When You Need It

If you only care that the command runs, you do not need to capture its output.

python
import subprocess

subprocess.run(["python3", "script.py"], check=True)

If you do want the output for later processing, capture_output=True or explicit stdout and stderr pipes are appropriate.

Avoid shell=True Unless You Need Shell Features

Sometimes people write:

python
subprocess.run("ls -l", shell=True)

That can work, but it brings shell parsing and injection risk. Prefer list-based arguments unless you actually need shell features such as wildcard expansion, pipelines, or shell built-ins.

If user input is involved, avoiding shell=True is especially important.

Use Popen for Long-Running or Interactive Cases

subprocess.run is best for simple request-and-wait execution. If you need streaming I/O, interaction, or more control over the process lifetime, use subprocess.Popen.

python
1import subprocess
2
3process = subprocess.Popen(["python3", "worker.py"])
4process.wait()

That lower-level API is more powerful, but most code should start with run and move to Popen only when needed.

Common Pitfalls

  • Using os.system when structured subprocess control is required.
  • Passing a shell string with shell=True without understanding the security implications.
  • Ignoring the command exit status and treating failed commands as though they succeeded.
  • Capturing output unnecessarily and complicating code that only needed to run a command.
  • Reaching for Popen when subprocess.run would have solved the problem more simply.

Summary

  • In Python, subprocess.run is the usual answer for executing external commands.
  • Pass commands as a list of arguments when possible.
  • Use check=True when failure should stop the workflow.
  • Avoid shell=True unless you genuinely need shell semantics.
  • Use Popen only for more advanced process-control cases.

Course illustration
Course illustration

All Rights Reserved.