Programmer
Programmer

Reputation: 8717

Get the stderr and stdout in separate variables with exit status

I have to write a Python code for my production server hence trying to clear my concept via an example. The Python script has to invoke and execute a bash shell script - the shell script may dump a lot of message and exit either successfully or un-successfully uisng exit (2) system call. As such I am trying via below method:

import subprocess
try:
        output = subprocess.check_output(
                'bash mytest',
            shell=True,
            stderr=subprocess.STDOUT,
        )
        print 'Have %d bytes in output' % len(output)
        print output
except subprocess.CalledProcessError, e:
        print "Error String:", e.output
        print "Error Return code:", e.returncode

The code works fine but is it the correct way to call given the fact that the script can print hundreds of line (using echo).

Will the output variable have both stderr and stdout message as printed by bash script? Can I get the stderr and stdout messages of bash script in separate variables - keeping in mind that there might not be any stderr messages at all if scripts runs successfully?

Also should I assume that in case the exception subprocess.CalledProcessError is not thrown the return code is 0 (SUCCESS)?

Is there a better way to implement the same - will this methodology ensure that the Python script would wait until completion of the bash script?

Thanks in advance.

Upvotes: 2

Views: 2030

Answers (2)

wildcard
wildcard

Reputation: 21

I had this same issue and solved it by Pynchia's suggestion from the PMOTW link to make the simple example below for what worked for me:

import subprocess
proc = subprocess.Popen('<your command>', shell=True, 
                       stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
print(stdout)           
print(stderr)           # can be found in stdout if stderr=subprocess.STDOUT
print(proc.returncode)  # 0 if success, 1 or non-zero if error

Upvotes: 2

Dima Tisnek
Dima Tisnek

Reputation: 11779

If you want to capture both stdout and stderr you have to use a lower-level function. Expanding on the source code of check_output, here's what you can do:

process = Popen(stdout=PIPE, stderr=PIPE, *popenargs, **kwargs)
output, stderr = process.communicate()
retcode = process.poll()
if retcode:
    cmd = kwargs.get("args")
    if cmd is None:
        cmd = popenargs[0]
    raise CalledProcessError(retcode, cmd, output=stderr)  # or your own exception
return output

Upvotes: 0

Related Questions