Computer Science Atlas
Snippets

Python 3: Get and Check Exit Status Code (Return Code) from subprocess.run()

Part 2 of a Series: subprocess.run()
July 12, 2021
 
Articles in Series: subprocess.run()
  1. Python 3: Execute a System Command Using subprocess.run()
  2. Current Article
    Python 3: Get and Check Exit Status Code (Return Code) from subprocess.run()
  3. Python 3: Get Standard Output and Standard Error from subprocess.run()
  4. Python 3: Standard Input with subprocess.run()
  5. Python 3: Using Shell Syntax with subprocess.run()
  6. Python 3: Specify Environment Variables in subprocess.run()
Table of Contents

Get Exit Status Code

When running a command using subprocess.run(), the exit status code of the command is available as the .returncode property in the CompletedProcess object returned by run():

from subprocess import run

p = run( [ 'echo', 'Hello, world!' ] )
print( 'exit status code:', p.returncode )
1
2
3
4
from subprocess import run

p = run( [ 'echo', 'Hello, world!' ] )
print( 'exit status code:', p.returncode )

Check Exit Status Code and Raise Error if Non-Zero

Manual Check

If we want our script to stop running and raise an error if the subprocess returns a non-zero exit status code, we could manually check the returncode property of the CompletedProcess object that run() returns:

from subprocess import run

print( 'Running command...' )
p = run( [ 'cat', '/foo' ] )
if p.returncode != 0:
    raise Exception( f'Invalid result: { p.returncode }' )

# If `cat /foo` fails above, we won't get here.
print( 'All done!' )
1
2
3
4
5
6
7
8
9
from subprocess import run

print( 'Running command...' )
p = run( [ 'cat', '/foo' ] )
if p.returncode != 0:
    raise Exception( f'Invalid result: { p.returncode }' )

# If `cat /foo` fails above, we won't get here.
print( 'All done!' )

check=True Option (Shorter Code)

But the shorter way to accomplish the same thing is to just set check=True when we call run():

from subprocess import run

print( 'Running command...' )
run( [ 'cat', '/foo' ], check=True )

# If `cat /foo` fails above, we won't get here.
print( 'All done!' )
1
2
3
4
5
6
7
from subprocess import run

print( 'Running command...' )
run( [ 'cat', '/foo' ], check=True )

# If `cat /foo` fails above, we won't get here.
print( 'All done!' )

Assuming we don't have a file /foo on our system, cat /foo will return a non-zero exit status code. If we run the code above on a Linux-based system, we'll see output like this:

Running command...
cat: /foo: No such file or directory
Traceback (most recent call last):
  File "test.py", line 4, in 
    run( [ 'cat', '/foo' ], check=True )
  File "/usr/lib/python3.8/subprocess.py", line 512, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['cat', '/foo']' returned non-zero exit status 1.

Note that All Done! is never printed because the script raised an error before it got to line 5.

If we omit the check=True option:

from subprocess import run

print( 'Running command...' )
run( [ 'cat', '/foo' ] )

# Even if `cat /foo` fails above, we will always get here.
print( 'All done!' )
1
2
3
4
5
6
7
from subprocess import run

print( 'Running command...' )
run( [ 'cat', '/foo' ] )

# Even if `cat /foo` fails above, we will always get here.
print( 'All done!' )

check defaults to False, so we won't see an error message, and we will see the All done! line:

Running command...
cat: /foo: No such file or directory
All done!