CertGrid CertGrid
Hands-on Lab·Python Automation for IT

Python subprocess Without a Shell

Automation spends a lot of its time running other programs. `subprocess.run` with a list of arguments does that with no shell involved, which means no quoting, no glob expansion and no injection. `shell=True` hands your string to `/bin/sh` instead - and this guide shows exactly what that costs, with a captured command injection that removes a file it was never asked to touch.

OS and Process Automation Guide 17 of 39 Intermediate

Written against the versions above. `subprocess.run` has been the recommended interface since Python 3.5, and `capture_output=True` since 3.7. `os.system` and the old `commands` module are gone or should be treated as such.

Everything on this page runs on the control node. Any machine with Python 3 will do.
Server NameIP AddressOSRolesCPURAMHDD
RUNNER01192.168.0.27Ubuntu 26.04 LTSControl node - every script in this path runs here2 Core4 GB50 GB

Before you start

  1. The one call worth remembering

  2. A list, not a string

  3. What a shell would have done to that

  4. And why shell=True is a security decision

  5. The command that does not exist

  6. A pipeline, without a shell

  7. shlex, when a command really does arrive as a string

Official sources