1. What is Python’s subprocess Module?
Overview
The subprocess
module in Python is a powerful tool for executing system commands and external programs from within Python. By using this module, you can manage standard input/output and processes, making it easy to integrate external programs with Python scripts. It provides a safer and more flexible way to control processes compared to the traditional os.system()
or commands
modules.
Main Use Cases
- Executing shell commands: Running simple system commands.
- Process management: Executing external programs and redirecting standard input/output.
- Asynchronous processing: Managing long-running tasks and parallel execution.
2. Basic Usage: subprocess.run()
Basic Usage
The subprocess.run()
function allows you to execute system commands from within Python in a simple way. For example, to list files in a directory, you can use the following code:
import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)
This code executes the ls -l
command, captures its output in stdout
, and processes it within Python. The capture_output=True
option captures the standard output, and text=True
ensures the result is handled as a string.
Error Handling
When using subprocess.run()
, you can retrieve error messages using stderr
if the command fails. Additionally, you can check the success of execution with returncode
.
result = subprocess.run(['ls', 'nonexistentfile'], capture_output=True, text=True)
if result.returncode != 0:
print(f"Error: {result.stderr}")
In this example, if a nonexistent file is specified, an error message will be displayed via standard error.

3. Asynchronous Execution: subprocess.Popen()
Asynchronous Processing with Popen
Since subprocess.run()
is a synchronous operation, the Python program cannot proceed to the next step until the command execution is complete. However, using subprocess.Popen()
, you can execute processes asynchronously and perform other tasks simultaneously.
import subprocess
proc = subprocess.Popen(['sleep', '5'], stdout=subprocess.PIPE)
print("Process started")
proc.wait()
print("Process completed")
In this code, the sleep 5
command runs asynchronously, allowing other tasks to proceed while it is executing.
Controlling Standard Input and Output
With Popen
, you can precisely control standard input and output redirection. For example, the following code reads data from a file, processes it with the cat
command, and writes the result to another file.
with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
proc = subprocess.Popen(['cat'], stdin=infile, stdout=outfile)
proc.wait()
This allows you to redirect the standard input and output of external commands to files for processing.
4. Use Cases: Automation Scripts
File Backup
The subprocess
module is highly useful for automating system management tasks and periodic operations. For example, the following script automatically copies files to a backup directory:
import subprocess
files_to_backup = ['file1.txt', 'file2.txt', 'file3.txt']
backup_dir = '/backup/directory/'
for file in files_to_backup:
subprocess.run(['cp', file, backup_dir])
This script copies specified files to a backup folder. Creating simple scripts like this can help automate routine backup tasks.
Usage in CI/CD Pipelines
The subprocess
module is also commonly used in Continuous Integration (CI) and Continuous Deployment (CD) environments. It can be incorporated into automation pipelines to execute test scripts and handle deployment processes. For instance, it can be used to automatically run test scripts and proceed to the next step only if the tests pass.

5. Security and Best Practices
Risks of shell=True
The shell=True
option is used to execute commands through the shell, but it comes with security risks. Especially when passing external input directly, there is a danger of shell injection attacks. Using shell=False
reduces this risk.
import subprocess
# Recommended usage (safe)
subprocess.run(['ls', '-l'])
# shell=True (use with caution)
subprocess.run('ls -l', shell=True)
Cross-Platform Compatibility
System commands may vary across different operating systems. You can use Python’s platform
module to determine the OS and switch commands accordingly.
import platform
import subprocess
if platform.system() == "Windows":
subprocess.run(['dir'], shell=True)
else:
subprocess.run(['ls', '-l'])
6. Troubleshooting and Debugging
Common Errors and Solutions
When using subprocess
, errors such as “file not found” or “permission denied” are common. These can be captured using stderr
, and you can check returncode
to get details about the error.
Debugging Tips
The check=True
option raises an exception if the command fails, helping you detect issues early. Capturing standard output and error messages for logging also makes debugging easier.
import subprocess
try:
result = subprocess.run(['ls', '-l'], check=True, capture_output=True, text=True)
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"An error occurred: {e}")
7. Asynchronous Processing with asyncio
Asynchronous Processing Using asyncio
By using asyncio
, you can integrate subprocess
with asynchronous processing, allowing multiple processes to run in parallel. The example below executes the ls
command asynchronously and captures its output.
import asyncio
import subprocess
async def run_command():
proc = await asyncio.create_subprocess_exec('ls', '-l',
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run_command())
This code executes the command asynchronously and processes the standard output and error output. Using asyncio
allows efficient management of asynchronous tasks.