Run a Shell Command and Capture Output in Python
Run a command and read its output with subprocess.run(capture_output=True, text=True). check=True raises on a non-zero exit, and shell=True is needed for pipes.
A script has to run another program and use what it prints.
import subprocess
r = subprocess.run(["ls", "/nonexistent"], capture_output=True, text=True)
print(r.returncode, repr(r.stdout), r.stderr.strip())
r = subprocess.run(["echo", "héllo"], capture_output=True, text=True, check=True)
print(repr(r.stdout))
try:
subprocess.run(["false"], check=True)
except subprocess.CalledProcessError as e:
print("raised:", e)
r = subprocess.run("echo hi | tr a-z A-Z", shell=True, capture_output=True, text=True)
print(r.stdout.strip())2 '' ls: cannot access '/nonexistent': No such file or directory
'héllo\n'
raised: Command '['false']' returned non-zero exit status 1.
HIsubprocess.run waits for the command and returns a CompletedProcess. With capture_output=True the output and error streams are collected in stdout and stderr, and text=True decodes them to strings, so the accented word came back as a string with its trailing newline. A failed ls has return code 2 with its message in stderr. Adding check=True turns a non-zero exit into CalledProcessError, as the false example shows. Both keywords need Python 3.7 or later. See subprocess.run.
Pass the command as a list, which avoids the shell and its quoting. shell=True is needed for a pipe, as in the last call, but with input from outside it opens the door to command injection. The output is held in memory, so use Popen for very large or endless output.