Here's the Pythonic way to capture the output of a command with subprocess.Popen:
import subprocess
process = subprocess.Popen(["cmd", "arg"], stdout=subprocess.PIPE)
# And as Simply Red would say: "If you don't know 'decode' by now..."output = process.communicate()[0].decode()
Enhanced output capture: exceptions and error handling
Dealing with errors as they come
Receiving errors from your processes should be as easy as ordering a drink at Starbucks:
try:
# Let's go process some coffee... process = subprocess.Popen(["brew", "coffee"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = process.communicate()
# If the coffee (command) hasn't brewed (executed) well...if process.returncode != 0:
print(f"Spilled the coffee (error): {error.decode()} 😞")
else:
print(f"Coffee is ready (output): {output.decode()} ☕️")
except Exception as e:
print(f"Couldn't brew the coffee (command failed): {str(e)}")
Tips & tricks: command arguments, security & more
Crafting command arguments
Passing the command and its arguments as a list instead of a string helps to avoid shell injection attacks:
command = ["brew", "coffee"]
process = subprocess.Popen(command, stdout=subprocess.PIPE)
# Be sure to ".decode()" your coffee!output = process.communicate()[0].decode("utf-8")
Working with command execution
Ensuring a successful command run
Here, we're handling timeouts and interactive commands, which are cooler than cucumbers in a bowl of hot sauce:
process = subprocess.Popen([r"/path/to/cool/command"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
try:
output, _ = process.communicate(b'data to process here (input)\n', timeout=9)
except subprocess.TimeoutExpired:
process.kill()
output, _ = process.communicate() # Plan B...