86

I am using:

grepOut = subprocess.check_output("grep " + search + " tmp", shell=True)

To run a terminal command, I know that I can use a try/except to catch the error but how can I get the value of the error code?

I found this on the official documentation:

 exception subprocess.CalledProcessError

    Exception raised when a process run by check_call() or check_output() returns a non-zero exit status.

    returncode

        Exit status of the child process.

But there are no examples given and Google was of no help.

0

6 Answers 6

101

You can get the error code and results from the exception that is raised.

This can be done through the fields returncode and output.

For example:

import subprocess

try:
    grepOut = subprocess.check_output("grep " + "test" + " tmp", shell=True)                       
except subprocess.CalledProcessError as grepexc:                                                                                                   
    print("error code", grepexc.returncode, grepexc.output)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you exactly what I wanted. But now I am wondering, is there a way to get a return code without a try/except? IE just get the return code of the check_output, whether it is 0 or 1 or other is not important to me and I don't actually need to save the output.
No problem. Unfortunately, check_output will always throw CalledProcessError as long as an error code is non-zero. This means that if you don't want the program to suddenly terminate, you will need a try/except clause. You can however just use a "pass" statement when you get to the except clause if you don't care about the error code.
56

Python 3.5 introduced the subprocess.run() method. The signature looks like:

subprocess.run(
  args, 
  *, 
  stdin=None, 
  input=None, 
  stdout=None, 
  stderr=None, 
  shell=False, 
  timeout=None, 
  check=False
)

The returned result is a subprocess.CompletedProcess. In 3.5, you can access the args, returncode, stdout, and stderr from the executed process.

Example:

>>> result = subprocess.run(['ls', '/tmp'], stdout=subprocess.DEVNULL)
>>> result.returncode
0

>>> result = subprocess.run(['ls', '/nonexistent'], stderr=subprocess.DEVNULL)
>>> result.returncode
2

3 Comments

I reckon this is the most up-to-date approach. The syntax is much more simple and intuitive and was probably added for just that reason.
According to docs.python.org/3/library/subprocess.html#subprocess.run: "If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured."
yes, and it is a mistake to use check=True and put the subprocess.run() inside a try/except construct, since the return value is never set. Better to just do result=subprocess.run(); if result.returncode==0: success; else: failure, then you have result with all the fields to print or whatever
37

is there a way to get a return code without a try/except?

check_output raises an exception if it receives non-zero exit status because it frequently means that a command failed. grep may return non-zero exit status even if there is no error -- you could use .communicate() in this case:

from subprocess import Popen, PIPE

pattern, filename = 'test', 'tmp'
p = Popen(['grep', pattern, filename], stdin=PIPE, stdout=PIPE, stderr=PIPE,
          bufsize=-1)
output, error = p.communicate()
if p.returncode == 0:
   print('%r is found in %s: %r' % (pattern, filename, output))
elif p.returncode == 1:
   print('%r is NOT found in %s: %r' % (pattern, filename, output))
else:
   assert p.returncode > 1
   print('error occurred: %r' % (error,))

You don't need to call an external command to filter lines, you could do it in pure Python:

with open('tmp') as file:
    for line in file:
        if 'test' in line:
            print line,

If you don't need the output; you could use subprocess.call():

import os
from subprocess import call
try:
    from subprocess import DEVNULL # Python 3
except ImportError: # Python 2
    DEVNULL = open(os.devnull, 'r+b', 0)

returncode = call(['grep', 'test', 'tmp'], 
                  stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL)

Comments

5

Note that since Python 3.5 it is better to use subprocess.run() :

import subprocess

grepOut = subprocess.run(['grep', search, 'tmp'], shell=True) ## Only use shell=True if necessary

This will generate a subprocess.CompletedProcess instance which will be stored at grepOut. Then, and finally answering your question, you can get the return value from subprocess.run() like this:

grepOut.returncode

which will be equal to 0 if the command was successful, and not equal to 0 if it failed.

Finally, for completeness sake, you could even handle the error by means of a try/except block using the method check_returncode() from subprocess.CompletedProcess class:

try:
    ## Add argument `capture_output=True` if you want to store the output of the command
    grepOut = subprocess.run(['grep', search, 'tmp'], shell=True)
    grepOut.check_returncode()

except subprocess.CalledProcessError as err:
    ## If returncode is non-zero, raise a CalledProcessError and print this message
    print(f"Oops, something went wrong. Error code: {err.returncode}")

Hope it is clear enough.

Comments

4

To get both output and return code (without try/except) simply use subprocess.getstatusoutput (Python 3 required)

5 Comments

please read stackoverflow.com/help/how-to-answer on how to write a good answer.
Done. Now what?
Its not just reading, its about implementing it on your answer.
I guess I just don't see what's wrong with it. Please tell me how you think it should be improved.
You could provide an example of the method you mentioned being used. However, your answer brought another method to my attention that I didn't know about yet so it's already been valuable to me anyway.
2

In Python 2 - use commands module:

import command
rc, out = commands.getstatusoutput("ls missing-file")
if rc != 0: print "Error occurred: %s" % out

In Python 3 - use subprocess module:

import subprocess
rc, out = subprocess.getstatusoutput("ls missing-file")
if rc != 0: print ("Error occurred:", out)

Error occurred: ls: cannot access missing-file: No such file or directory

1 Comment

This is the best option. subprocess.run() may throw exceptions if the command is not found on the machine (e.g. nvcc). This approach will hide all of that in the returncode and not throw an exception.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.