Get exit code and stderr from subprocess call
Try this version:
import subprocess
try:
output = subprocess.check_output(
cmnd, stderr=subprocess.STDOUT, shell=True, timeout=3,
universal_newlines=True)
except subprocess.CalledProcessError as exc:
print("Status : FAIL", exc.returncode, exc.output)
else:
print("Output: \n{}\n".format(output))
This way you will print the output only if the call was successful.
In case of a CalledProcessError
you print the return code and the output.
The accepted solution covers the case in which you are ok mixing stdout
and stderr
, but in cases in which the child process (for whatever reason) decides to use stderr
IN ADDITION to stdout
for a non failed output (i.e. to output a non-critical warning), then the given solution may not desirable.
For example, if you will be doing additional processing on the output, like converting to JSON, and you mix in the stderr
, then the overall process will fail since the output will not be pure JSON because of the added stderr
output.
I've found the following to work in that case:
cmd_args = ... what you want to execute ...
pipes = subprocess.Popen(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#If you are using python 2.x, you need to include shell=True in the above line
std_out, std_err = pipes.communicate()
if pipes.returncode != 0:
# an error happened!
err_msg = "%s. Code: %s" % (std_err.strip(), pipes.returncode)
raise Exception(err_msg)
elif len(std_err):
# return code is 0 (no error), but we may want to
# do something with the info on std_err
# i.e. logger.warning(std_err)
# do whatever you want with std_out
# i.e. json.loads(std_out)
Both of the proposed solutions either mix the stdout/stderr, or use Popen
which isn't quite as simple to use as check_output
. However, you can accomplish the same thing, and keep stdout/stderr separate, while using check_output
if you simply capture stderr by using a pipe:
import sys
import subprocess
try:
subprocess.check_output(cmnd, stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
print('exit code: {}'.format(e.returncode))
print('stdout: {}'.format(e.output.decode(sys.getfilesystemencoding())))
print('stderr: {}'.format(e.stderr.decode(sys.getfilesystemencoding())))
In this example, since we captured stderr, it's available in the exception's stderr
attribute (without capturing with the pipe, it would just be None
).