The Raspberry Pi is a popular single-board computer that runs Linux, with Python as its official programming language. As a Raspberry Pi user, you‘ll likely need to execute Linux commands regularly for tasks like file management, user administration, installing packages etc.

While you can always run these commands directly in the terminal, it can get tedious entering the terminal over and over, especially if executing commands from within Python scripts. Fortunately, Python provides simple ways to run system commands from within your code itself.

In this comprehensive guide, we‘ll explore the two main methods to execute shell commands programmatically in Python on Raspberry Pi:

  1. Using the os module
  2. Using the subprocess module

We‘ll see examples of running common Linux commands like ls, mkdir, adduser etc. using both these approaches.

Overview of OS and Subprocess Modules

The os module is a built-in Python module that provides convenient access to operating system functionality. It contains functions like os.system(), os.popen() etc. for executing system commands.

The subprocess module allows spawning new processes to run commands. It gives more flexibility than os module and handles complex scenarios like piping output between multiple commands.

So the os module is simpler, while subprocess module is more full-featured. We‘ll cover usage of both in this guide.

1. Executing Commands with os module

To use the os module in Python, first import it:

import os

The os module provides two chief ways to run shell commands:

  1. os.system()
  2. os.popen()

Let‘s explore them one by one with examples.

1.1 os.system()

The os.system() method executes the command passed to it in a subshell.

Here is the syntax:

os.system(‘command‘)

Let‘s see some examples of running common Linux commands with os.system().

Print current working directory:

import os

os.system(‘pwd‘)

This will print the output directly to the terminal.

List files in directory:

import os

os.system(‘ls‘)

Create a directory:

import os

os.system(‘mkdir testdirectory‘) 

Add a new user:

import os

os.system(‘sudo adduser newuser‘)

And so on.

One limitation of os.system() is that it doesn‘t allow capturing the output programmatically for further processing. For that, os.popen() is useful.

1.2 os.popen()

The os.popen() method opens a pipe to the command passed to it and returns a file handle. We can use this handle to read the output of the command.

Here is how to use it:

import os

stream = os.popen(‘command‘)
output = stream.read()

The command‘s output is stored in the output variable as a string.

Let‘s see some examples.

Store ls output:

import os

stream = os.popen(‘ls‘)
output = stream.read()
print(output)

We can process the stored output further according to our needs.

Count files in directory:

import os

stream = os.popen(‘ls | wc -l‘)  
output = stream.read()
count = int(output)

print(f"Total files: {count}") 

Here we piped the ls output to wc -l to count lines, stored it in a variable, converted to integer, and printed the count.

So with os.popen(), you can read command outputs in your Python code for further processing that would be difficult with os.system().

2. Executing Commands with subprocess

The subprocess module provides more flexibility in running shell commands from Python code. It allows spawning child processes asynchronously and offers better ways to feed input or pipe output between processes.

To start using subprocess, import it:

import subprocess

The primary method that subprocess provides for running commands is subprocess.run().

2.1 subprocess.run()

The subprocess.run() method runs the command passed to it in a subprocess and returns a CompletedProcess object.

Here is its standard syntax:

result = subprocess.run([‘command‘, ‘arg1‘, ‘arg2‘])  

We pass the command and its arguments as a list to run().

Let‘s see some examples:

List files:

import subprocess

result = subprocess.run([‘ls‘, ‘-l‘])

Print disk usage:

import subprocess 

result = subprocess.run([‘df‘, ‘-h‘])

The result object contains useful information like the command‘s exit code, output etc. which we can access:

print(f"Exit code: {result.returncode}")  
print(f"Output: {result.stdout}")
print(f"Errors: {result.stderr}")

By default, the output streams are buffered. To print the output directly to terminal, use:

result = subprocess.run([‘ls‘], stdout=subprocess.PIPE, text=True)
print(result.stdout)

The text argument decodes the bytes output to a string.

We can also provide shell-style string commands instead of list format:

subprocess.run(‘ls -l | grep .py‘, shell=True)

The shell=True argument runs the command string through the shell.

2.2 Interactive Input/Output

A great benefit of the subprocess module is the ability pipe input or output interactively between processes.

Let‘s see an example of providing input to a command via stdin.

Pipe input to bash:

import subprocess

proc = subprocess.Popen([‘bash‘], stdin=subprocess.PIPE) 
proc.stdin.write(b‘echo Hello World\n‘)
proc.stdin.write(b‘exit\n‘)

output = proc.communicate()[0]
print(output.decode().strip())

Here we get a process handle via Popen(), write some input commands to it, then print the output after the process exits.

Similarly, we can pipe output of one process as input to another using subprocess pipes.

Count files:

import subprocess

proc1 = subprocess.Popen([‘ls‘], stdout=subprocess.PIPE)
proc2 = subprocess.Popen([‘wc‘, ‘-l‘], stdin=proc1.stdout, 
                          stdout=subprocess.PIPE)

output = proc2.communicate()[0]
print(f"Total files: {output.decode().strip()}")

So subprocess makes it easy to handle input/output programmatically with Python.

Best Practices for Running Commands

When executing system commands from Python, keep in mind:

  • Always sanitize user input before substituting into commands
  • Prefer subprocess over os module for better control and output handling
  • Consider edge cases carefully – exit codes, errors, output buffering etc
  • Don‘t assume commands succeeded, check return codes
  • Validate permissions before file/dir operations

Adopting these best practices will make your script‘s command execution more secure, robust and deterministic.

Conclusion

Executing Linux commands from within Python scripts is extremely useful for automating admin tasks, implementing CLI tools, and simplifying workflows.

We learned two approaches for running system commands using Python on Raspberry Pi:

  1. The os module – provides os.system() and os.popen()
  2. The subprocess module – gives more flexibility via subprocess.run() etc.

The os module offers a simple interface for basic command execution. Subprocess gives finer-grained control over spawning processes and managing input/output streams.

So in summary:

  • Use os.system() for fire-and-forget command running
  • Use os.popen() to programmatically access command output
  • Use subprocess when you need better output handling or process control

By mastering these methods, you can easily automate almost any Linux administration or command line task with Python scripts on your Raspberry Pi.

Similar Posts