How to interpret status code in Python commands.getstatusoutput()
Solution 1
There is a set of functions in os
module (os.WIFCONTINUED
, os.WIFSTOPPED
, os.WTERMSIG
, os.WCOREDUMP
, os.WIFEXITED
, os.WEXITSTATUS
, os.WIFSIGNALED
, os.WSTOPSIG
), which correspond to macros from wait(2) manual. You should use them to interpret the status code.
For example, to get the exit code you should use os.WEXITSTATUS(status)
A better idea would be to switch to subprocess
module.
Solution 2
Wow. The insight that it was multiplying by 256 got me there. Searching for "python commands +256" got me to a Python Module Of The Week article which explains what's going on.
Here's a snippet from that page:
The function getstatusoutput() runs a command via the shell and returns the exit code and the text output (stdout and stderr combined). The exit codes are the same as for the C function wait() or os.wait(). The code is a 16-bit number. The low byte contains the signal number that killed the process. When the signal is zero, the high byte is the exit status of the program. If a core file was produced, the high bit of the low byte is set.
And some of Doug's code:
from commands import *
def run_command(cmd):
print 'Running: "%s"' % cmd
status, text = getstatusoutput(cmd)
exit_code = status >> 8
signal_num = status % 256
print 'Signal: %d' % signal_num
print 'Exit : %d' % exit_code
print 'Core? : %s' % bool(exit_code / 256)
print 'Output:'
print text
print
run_command('ls -l *.py')
run_command('ls -l *.notthere')
run_command('echo "WAITING TO BE KILLED"; read input')
Solution 3
Looking at commands.py
:
def getstatusoutput(cmd):
"""Return (status, output) of executing cmd in a shell."""
import os
pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
text = pipe.read()
sts = pipe.close()
if sts is None: sts = 0
if text[-1:] == '\n': text = text[:-1]
return sts, text
We see sts
holds the value of os.popen(...).close()
. Looking at that documentation, os.popen(...).close()
returns the value of os.wait
:
os.wait()
Wait for completion of a child process, and return a tuple containing its pid and exit status indication: a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced. Availability: Unix.
Emphasis was mine. I agree that this "encoding" isn't terribly intuitive, but at least it was fairly obvious at a glance that it was being multiplied/bit-shifted.
Shrey Shivam
Geek. Hiker. Cook. Voracious reader. Sometime writer. Python, BASH, Linux, command-line in general -- all deep geeky loves of mine. (Currently learning C.)
Updated on June 07, 2022Comments
-
Shrey Shivam almost 2 years
In a related question, I asked where to find the documentation for the C function "wait." This was an attempt to figure out return codes for the commands.getstatusoutput() module. Stackoverflow came through, but the documentation didn't help. Here's what puzzles me:
#!/usr/bin/python import commands goodcommand = 'ls /' badcommand = 'ls /fail' status, output = commands.getstatusoutput(goodcommand) print('Good command reported status of %s' % status) status, output = commands.getstatusoutput(badcommand) print('Bad command reported status of %s' % status)
When run on OS X (Leopard) I get the following output: (Which matches the documentation.)
$ python waitest.py Good command reported status of 0 Bad command reported status of 256
On OS X, doing an "ls /fail ; echo $?" gets the following output:
$ ls /fail ; echo $? ls: /fail: No such file or directory 1
When run on Linux (Ubuntu Hardy) I get the following output:
$ python waitest.py Good command reported status of 0 Bad command reported status of 512
On Ubuntu, doing "ls /fail" gets a 2:
$ ls /fail ; echo $? ls: cannot access /fail: No such file or directory 2
So Python appears to be multiplying status codes by 256. Huh? Is this documented somewhere?
-
CaffeineAddiction over 8 yearsthe return of os.system(cmd) seems to work the same way
insight that it was multiplying by 256
-
Ivan X over 8 yearsThank you for the emphasis, I was pretty confused by what I was seeing until I read this..