How to get the exit status set in a shell script in Python
I am running this code, but no matter the what exit status I am returning, I am getting result var as 0 (I think it’s returning whether the shell script ran successfully or not). How can I fetch the exit status that I am setting in the shell script in the Python script?
3 Answers 3
import subprocess result = subprocess.Popen("./compile_cmd.sh") text = result.communicate()[0] return_code = result.returncode
To complement cptPH’s helpful answer with the recommended Python v3.5+ approach using subprocess.run() :
import subprocess # Invoke the shell script (without up-front shell involvement) # and pass its output streams through. # run()'s return value is an object with information about the completed process. completedProc = subprocess.run('./compile_cmd.sh') # Print the exit code. print(completedProc.returncode)
import subprocess proc = subprocess.Popen("Main.exe",stdout=subprocess.PIPE,creationflags=subprocess.DETACHED_PROCESS) result,err = proc.communicate() exit_code = proc.wait() print(exit_code) print(result,err)
In subprocess.Popen -> creation flag is used for creating the process in detached mode if you don’t wnat in detached more just remove that part.
subprocess.DETACHED_PROCESS -> run the process outside of the python process
with proc.communicate() -> you can get he output and the errors from that process proc.wait() will wait for the process to finish and gives the exit code of the program.
Note: any commands between subprocess.popen() and proc.wait() will execute as usual at the wait call it will not execute further before the subprocess is finished.
How to get exit code when using Python subprocess communicate method?
How do I retrieve the exit code when using Python’s subprocess module and the communicate() method? Relevant code:
import subprocess as sp data = sp.Popen(openRTSP + opts.split(), stdout=sp.PIPE).communicate()[0]
8 Answers 8
Popen.communicate will set the returncode attribute when it’s done(*). Here’s the relevant documentation section:
Popen.returncode The child return code, set by poll() and wait() (and indirectly by communicate()). A None value indicates that the process hasn’t terminated yet. A negative value -N indicates that the child was terminated by signal N (Unix only).
So you can just do (I didn’t test it but it should work):
import subprocess as sp child = sp.Popen(openRTSP + opts.split(), stdout=sp.PIPE) streamdata = child.communicate()[0] rc = child.returncode
(*) This happens because of the way it’s implemented: after setting up threads to read the child’s streams, it just calls wait .
This example helped me, but it would be nice if examples didn’t do the «import subprocess as sp» pattern of importing something standard as an obscure abbreviation. While this trims 8 characters off the code that follows it, it also makes it difficult to understand and reuse.
@uglycoyote There’s no rule that says you have to copy and paste. Just retype it however you want, it’s like 4 like lines.
@uglycoyote you could also edit it to be something like from subprocess import Popen and then just use Popen instead of subprocess(or sp).Popen which I’d say probably increases readability and shortens lines
Yeah. must call process.communicate() and then assign returncode to some variable. If the assignment is done before calling communicate , is None .
Is it possible to show the return code without redirecting the pipe? I am calling a bash code and I would like to see the output in real time in the terminal
.poll() will update the return code.
child = sp.Popen(openRTSP + opts.split(), stdout=sp.PIPE) returnCode = child.poll()
In addition, after .poll() is called the return code is available in the object as child.returncode .
when I did this .poll() was empty. I had to run child.communicate() in the line above child.poll() for this to work.
I think you meant to use .wait() instead of .poll(), as per documentation: docs.python.org/3/library/subprocess.html. Note that .wait() takes an optional timeout param which can be convenient.
poll() will only update the return code if the child has terminated, otherwise it will return None — wait() is better here.
You should first make sure that the process has completed running and the return code has been read out using the .wait method. This will return the code. If you want access to it later, it’s stored as .returncode in the Popen object.
Just to point out a common misconception, you should avoid Popen always when you can. To quote the documentation,
The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.
If you just want to run a subprocess and wait for it to finish, that’s a single line of code with subprocess.run or its legacy siblings subprocess.call and subprocess.check_output , and you don’t need to copy/paste and/or understand the intricacies of the communicate and wait etc methods required around the low-level Popen object.
import subprocess proc = subprocess.run( [openRTSP] + opts.split(), capture_output=True, # avoid having to explicitly encode text=True) data = proc.stdout result = proc.returncode
If you don’t want to capture the output from the process, maybe replace capture_output=True with stdout=subprocess.DEVNULL (and perhaps similarly for stderr ); in the absence of either, the output will simply be displayed to the user, outside of Python’s control.
Also, unless your options in opts are completely trivial, generally replace the regular string split() here with shlex.split() which understands how to cope with quoted strings.
subprocess.check_output return code
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.
6 Answers 6
You can get the error code and results from the exception that is raised.
This can be done through the fields returncode and output .
import subprocess try: grepOut = subprocess.check_output("grep " + "test" + " tmp", shell=True) except subprocess.CalledProcessError as grepexc: print("error code", grepexc.returncode, grepexc.output)
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.
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.
>>> result = subprocess.run(['ls', '/tmp'], stdout=subprocess.DEVNULL) >>> result.returncode 0 >>> result = subprocess.run(['ls', '/nonexistent'], stderr=subprocess.DEVNULL) >>> result.returncode 2
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.»
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)