Almost every automation script needs to call git, a compiler, ffmpeg or another tool.
subprocess.run(args) starts a program, waits for it to finish, and returns a CompletedProcess object. Pass the command as a list: the program name first, then each argument as its own element.
subprocess.run(["git", "status", "--short"])Each list element reaches the program exactly as written, with no shell in between, so spaces, quotes and $ in arguments need no escaping. The program is looked up on PATH.
The result has:
returncode: 0 means success by convention; anything else means failure.args: what you ran.stdout/stderr:Noneunless you asked to capture them (next lesson).
By default the child inherits your terminal, so its output appears directly on screen, and run blocks until it exits.
run is the recommended high-level API and covers most needs. Older functions such as call, check_call and check_output still exist and are thin wrappers around it. Avoid os.system in new code: it always goes through the shell and only gives you an encoded exit status.
To run another Python script portably, use sys.executable (the current interpreter) as the program instead of a hardcoded "python".
Example
import subprocess, sys
r = subprocess.run(["echo", "hello", "world with spaces"])
# hello world with spaces
print(r.returncode) # 0
print(r.args) # ['echo', 'hello', 'world with spaces']
r = subprocess.run([sys.executable, "-c", "import sys; sys.exit(3)"])
print(r.returncode) # 3
print(r.stdout) # None (not captured)Remember
- run() starts a program, waits, and returns a CompletedProcess
- Pass the command as a list of separate arguments
- returncode 0 means success
Watch out for
- Passing one string like 'ls -l' without shell=True; on POSIX it looks for a program literally named 'ls -l'.