How to get exit code when using Python subprocess communicate method?
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
.
How to get exit code from subprocess.Popen?
According to the linked to documentation
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).
You have not called poll
or wait
so returncode
won't be set.
On the other hand if you look in to the source code for fx check_output
you see that they are directly using the return value from poll
to examine the return code. They know that the process has terminated at that point because they have called wait
earlier. If you don't know that you would have to call the wait
method instead (but note the deadlock possibility noted in the documentation).
Normally the program will have terminated when you've read all of stdout/stderr, but that's not guaranteed and that may be what you're seeing. Either the program or the OS can close stdout
(and stderr
) before the process actually terminates and then by just calling poll
immediately after you've read all the output from the program might fail.
Why does subprocess.run return an exit code of 2 but no errors in log?
First of all it would be nice to know what OS you are using. Basically the stderr
and stdout
are file descriptors (1 and 2 by default.)
In your case the subcommand writes nothing to 1 and 2 file descriptors (so to stderr
and stdout
) and of course the return code is 2
.
If you run the following code:
import subprocess
result = subprocess.run(["echo", "test"])
print(result.returncode, result.stdout, result.stderr)
You get:
>>> python3 test.py
test
0 None None
It means the echo
runs correctly and writes the test
to the STDOUT but the result.stdout
doesn't contain it. This happens but you don't redirect the STDOUT of the command to a PIPE.
If you change the code to:
import subprocess
result = subprocess.run(["echo", "test"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(result.returncode, result.stdout, result.stderr)
You will get:
>>> python3 test.py
0 b'test\n' b''
So now the result.stdout
contains the STDOT of the called command in bytes. It is True for STDERR.
If a set the shell
parameter to True
, I can run invalid (not existed) command as you can see below:
import subprocess
result = subprocess.run(["invalid_cmd"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
print(result.returncode, result.stdout, result.stderr)
In this case the output is:
>>> python3 test.py
127 b'' b'/bin/sh: invalid_cmd: command not found\n'
It means the return code is 127 and the STDOUT is empty but the STDERR contains /bin/sh: invalid_cmd: command not found\n
message in bytes.
If you do the above things but you don't see any output then your called command doesn't write the STDOUT or STDERR so you should look into the called command.
Cannot get exit code when running subprocesses in python using Popen and start /wait
CMD's start
command always succeeds overall if it successfully executes the given command via CreateProcess
or ShellExecuteEx
. It succeeds even if it's instructed to /wait
and ends up setting %errorlevel%
to a non-zero value. You can see this by running (start /wait exit 1) && echo success
. The &&
operator only executes the right-hand expression if the left-hand expression succeeds.
To work around this, you can manually exit the initial shell using the !errorlevel!
value that gets set by start
. For example:
command = 'exit 1'
shell_path = os.environ.get('ComSpec', 'cmd.exe')
start_command = 'start "" /wait {}'.format(command)
cmdline = '"{shell}" /v:on /c "({command}) & exit !errorlevel!"'.format(
shell=shell_path, command=start_command)
proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Note that the above Popen
call does not use the shell=True
argument because the shell needs to be run manually with the /v:on
option. This enables delayed expansion of environment variables, using "!" instead of "%".
That said, you don't need the shell for your stated objective. Simply have the child process create a new console by passing the CREATE_NEW_CONSOLE
creation flag as follows:
proc = subprocess.Popen(args, creationflags=subprocess.CREATE_NEW_CONSOLE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Portable way to check if subprocess exit code indicates a success?
The docs for subprocess
effectively require that 0
means success, e.g. for subprocess.run
(the all-in-one high level synchronous API), when check=True
, the docs specify:
If check is true, and the process exits with a non-zero exit code, a
CalledProcessError
exception will be raised.
OpenVMS isn't actually a supported target for CPython, and all supported targets obey that rule to my knowledge.
Presumably the third-party OpenVMS port would have to include porting proper error-checking (even if it doesn't change the exit codes, check=True
should be changed to make it only raise the exception when the child fails). So the simplest solution would be to write your code as:
try:
proc = subprocess.run(..., check=True)
except subprocess.CalledProcessError:
# Handle failure here
and if OpenVMS didn't make check=True
work the logically correct way in their port, file a bug against them to make it logically match the intended behavior (exception raised when subprocess fails, even if docs say "non-zero"). Aside from that, your only option is checking sys.platform
and manually checking the error code a different way on OpenVMS (I have no idea what OpenVMS reports for sys.platform
, you'd have to check it yourself).
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.
subprocess.check_output return code
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)
Retrieving the output of subprocess.call()
Output from subprocess.call()
should only be redirected to files.
You should use subprocess.Popen()
instead. Then you can pass subprocess.PIPE
for the stderr, stdout, and/or stdin parameters and read from the pipes by using the communicate()
method:
from subprocess import Popen, PIPE
p = Popen(['program', 'arg1'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode
The reasoning is that the file-like object used by subprocess.call()
must have a real file descriptor, and thus implement the fileno()
method. Just using any file-like object won't do the trick.
See here for more info.
Related Topics
Beautifulsoup Not Grabbing Dynamic Content
Django Gunicorn Not Load Static Files
How to Change the Styles of Pandas Dataframe Headers
Google Fonts (Ttf) Being Ignored in Qtwebengine When Using @Font Face
How to Use Tailwindcss with Django
Does Python Have a Module to Convert CSS Styles to Inline Styles for Emails
Replicating Jupyter Notebook Pandas Dataframe HTML Printout
How to Customise Qgroupbox Title in Pyqt5
Add Custom CSS Styling to Model Form Django
How to Compile Opencv for iOS7 (Arm64)
Calling R Script from Python Using Rpy2
Alternative Way to Split a List into Groups of N
Pip Freeze Creates Some Weird Path Instead of the Package Version
How to Copy a 2D Array into a 3Rd Dimension, N Times
How to Get the Index of a Maximum Element in a Numpy Array Along One Axis