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
- Python3.14.4
- Control nodeUbuntu 26.04 LTS
- Managed hostsRHEL 10.0
- requests2.34.2
- paramiko5.0.0
- pytest9.1.1
- PyYAML6.0.3
- boto3 / botocore1.43.78
- TimeAbout 18 min
- Reviewed24 August 2026
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.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| RUNNER01 | 192.168.0.27 | Ubuntu 26.04 LTS | Control node - every script in this path runs here | 2 Core | 4 GB | 50 GB |
Before you start
-
The one call worth remembering
-
A list, not a string
-
What a shell would have done to that
-
And why shell=True is a security decision
-
The command that does not exist
-
A pipeline, without a shell
-
shlex, when a command really does arrive as a string