LESSON · 1 OF 5

The subprocess module

The subprocess module

Sometimes the tool you need already exists as a command: df, git, systemctl, kubectl. Rather than reimplement it, you run it from Python and work with what it prints. The subprocess module in the standard library does exactly that.

subprocess.run

The one function you'll reach for is subprocess.run. Pass it the command as a list, where the first item is the program and the rest are its arguments:

python
import subprocess

subprocess.run(["ls", "-l", "/etc"])

This runs ls -l /etc, and its output goes straight to your terminal, just as if you had typed the command yourself. run waits for the command to finish before your Python continues.

Why a list, not a string

Each argument is its own item in the list. You write ["ls", "-l"], not "ls -l". Python hands that list straight to the operating system as the program and its arguments, so nothing reinterprets your spaces or quotes.

There is another form, shell=True, that takes a single string and runs it through the shell:

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

It looks convenient, but it hands your string to a full shell, which interprets characters like ;, |, and $. If any part of that string comes from outside your program (a filename a user typed, a value from an API), someone can smuggle in extra commands. That's a command-injection bug. The next scenario looks at it in detail.

The habit to build: use the list form. Reach for shell=True only for a fixed string you wrote yourself, never with untrusted input.

What this node introduces

  • subprocess.run([...]) runs a command from a list of arguments.
  • The list form keeps arguments separate and avoids the shell.
  • shell=True runs a string through the shell and is risky with any input you don't control.
Spin up a fresh environment and practice live.
python-devops · fresh machine · ready in under a minute