How to Execute Shell Commands with Python

Advertisement

May 15, 2025 By Alison Perry

Sometimes in a Python project, you need to reach beyond the language and interact with the system itself—copy a file, ping a server, or run a command-line tool. You don’t have to switch languages or leave your script. Python gives you ways to run shell commands directly, whether it’s a simple one-liner or something more involved.

Some methods have been around for years and still work well; others are newer and offer more control, like capturing output or handling errors cleanly. The right choice depends on how much feedback you need and how the command fits into your code. This article covers nine practical ways to run shell commands in Python, from quick solutions to advanced options.

How to Easily Execute Shell Commands with Python?

Using os.system()

This one is basic. It’s part of the os module and has been around forever. It runs the command you give it as if you typed it in the terminal. But it doesn’t return the output—just the exit code.

import os

os.system('ls -l')

Use this if you only care whether the command succeeded. It's fine for simple jobs, but it's limited. You can't capture what the command prints unless you redirect it manually to a file.

Using subprocess.call()

This came later and offers more control. You pass it the command as a list or a string. It runs the command and returns the exit code. It doesn't capture output either unless you work around it.

import subprocess

subprocess.call(['ls', '-l'])

It’s more secure than os.system() because it avoids shell injection if you pass a list. That matters when building commands from user input.

Using subprocess.run()

This is the modern way. It arrived in Python 3.5 and cleaned things up. It can run a command, wait for it to finish, and capture the output if needed. It returns a CompletedProcess object that has details like return code, stdout, and stderr.

import subprocess

result = subprocess.run(['ls', '-l'], capture_output=True, text=True)

print(result.stdout)

This approach is cleaner and easier to debug. You get more feedback, and it’s not much more to write. For many tasks, this is the best balance.

Using subprocess.Popen()

This gives you even more control. It's for advanced cases—when you want to run something in the background, stream the output as it comes in, or handle stdin and stdout while the command runs.

import subprocess

process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, text=True)

for line in process.stdout:

print(line.strip())

This method is flexible, but a little more complex. You don't always need it, but it's good when you want to process output in real time.

Using commands.getoutput() (Python 2 only)

This one is obsolete. It was part of the commands module in Python 2 and used like this:

import commands

output = commands.getoutput('ls -l')

print(output)

You shouldn’t use it in modern code. It's not available in Python 3, and even in Python 2, it had security problems. Avoid unless you’re stuck with legacy code.

Using shlex.split() with subprocess

Sometimes, your command is in a string, and you want to split it properly—like the shell would—before passing it to the subprocess. That's where shlex helps. It parses the string into a list that avoids quoting errors.

import subprocess

import shlex

command = "ls -l /home/user"

args = shlex.split(command)

subprocess.run(args)

This is safer than just doing .split() on a space. It handles quotes and escapes correctly. It's not a way to run commands on its own, but it's helpful with subprocesses.

Using os.popen()

This one is older and returns a file-like object for reading the output. It’s less common now, and while it still works, subprocess.run() is usually better.

import os

output = os.popen('ls -l').read()

print(output)

It's simple but less powerful than the subprocess. You don't get an exit code or access to stderr, and it's not great for error handling. Use it for quick scripts or throwaway code.

Using pexpect for interactive shell programs

Some commands ask for input while they run—like passwords or confirmations. That’s where pexpect comes in. It’s not part of the standard library, so you need to install it.

import pexpect

child = pexpect.spawn('ftp ftp.gnu.org')

child.expect('Name .*: ')

child.sendline('anonymous')

child.expect('Password:')

child.sendline('[email protected]')

child.interact()

This module lets your Python code interact with programs like a person would—waiting for prompts and sending responses. It's useful for automation tasks where commands need interaction. A little heavier but necessary in some workflows.

Using Path().write_text() with shell redirection (indirect method)

This approach doesn’t run commands directly but lets you write shell scripts from Python and execute them using the shell itself. It’s handy when you want to script multiple steps, pass variables, or maintain portability.

from pathlib import Path

import subprocess

script = Path("temp_script.sh")

script.write_text("""#!/bin/bash

echo "This is a shell script run from Python"

ls -l

""")

script.chmod(0o755)

subprocess.run(["./temp_script.sh"])

You create a shell script from inside Python, make it executable, and run it. This is useful when you want the benefits of shell scripting while staying in the Python workflow. It's not always needed, but it can be a clean solution when you're generating or templating system commands.

Conclusion

Python gives you several ways to run shell commands without stepping outside your code. Whether you need something fast or more detailed, there’s a method that fits. For simple tasks where output doesn’t matter, os.system() works. If you need results or error handling, subprocess.run() is solid and straightforward. For commands needing interaction, pexpect helps automate input and output. These tools let you mix shell logic with Python without confusion. You don’t have to switch contexts or rewrite what already works in bash. Just call it, catch the result, and keep going. Python handles the rest, making it easy to blend scripting with control in a way that stays clean and readable.

Advertisement

You May Like

Top

How SmolVLM2 Makes Video Understanding Work on Any Device

SmolVLM2 brings efficient video understanding to every device by combining lightweight architecture with strong multimodal capabilities. Discover how this compact model runs real-time video tasks on mobile and edge systems

Jun 05, 2025
Read
Top

Getting Data in Order: Using ORDER BY in SQL

How the ORDER BY clause in SQL helps organize query results by sorting data using columns, expressions, and aliases. Improve your SQL sorting techniques with this practical guide

Jun 04, 2025
Read
Top

How a Director of Machine Learning Insights Shapes Business Decisions

What a Director of Machine Learning Insights does, how they shape decisions, and why this role is critical for any business using a machine learning strategy at scale

Jul 06, 2025
Read
Top

Stable Diffusion Explained Simply: From Noise to AI-Generated Images

Learn everything about Stable Diffusion, a leading AI model for text-to-image generation. Understand how it works, what it can do, and how people are using it today

May 20, 2025
Read
Top

Meet the Innovators: 9 Data Science Companies Making an Impact in the USA

Which data science companies are actually making a difference in 2025? These nine firms are reshaping how businesses use data—making it faster, smarter, and more useful

May 31, 2025
Read
Top

How MobileNetV2 Makes Deep Learning Work on Phones and Edge Devic-es

How MobileNetV2, a lightweight convolutional neural network, is re-shaping mobile AI. Learn its features, architecture, and applications in edge com-puting and mobile vision tasks

May 20, 2025
Read
Top

Use Llama 3.2 Locally With Built-In Image Understanding Support

Llama 3.2 brings local performance and vision support to your device. Faster responses, offline access, and image understanding—all without relying on the cloud

Jun 09, 2025
Read
Top

Streamline Machine Learning with Hugging Face + PyCharm Integration

How using Hugging Face + PyCharm together simplifies model training, dataset handling, and debugging in machine learning projects with transformers

May 14, 2025
Read
Top

Start Using Accelerate 1.0.0 For Faster, Cleaner Builds Today Now

Looking for faster, more reliable builds? Accelerate 1.0.0 uses caching to cut compile times and keep outputs consistent across environments

Jun 10, 2025
Read
Top

How Amazon Uses AI to Detect and Prevent Online Fraud

How Amazon is using AI to fight fraud across its marketplace. Learn how AI-driven systems detect fake sellers, suspicious transactions, and refund scams to enhance Amazon fraud prevention

Jul 23, 2025
Read
Top

Step-by-Step Guide to Building a Waterfall Chart in Excel

Learn how to create a waterfall chart in Excel, from setting up your data to formatting totals and customizing your chart for better clarity in reports

May 31, 2025
Read
Top

Why a Robotic Puppy Is Becoming a Must-Have in Dementia Care

Can a robotic puppy really help ease dementia symptoms? Investors think so—$6.1M says it’s more than a gimmick. Here’s how this soft, silent companion is quietly transforming eldercare

Jul 29, 2025
Read