Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to interpret status code in Python commands.getstatusoutput()

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?

like image 849
Schof Avatar asked Oct 08 '09 04:10

Schof


People also ask

What is commands Getstatusoutput?

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.

What are different commands in Python?

A. Some common Python commands are input, print, range, round, pip install, len, sort, loop commands like for and while so on and so forth.

How do you start a process in python?

How to Start a Process in Python? To start a new process, or in other words, a new subprocess in Python, you need to use the Popen function call. It is possible to pass two parameters in the function call. The first parameter is the program you want to start, and the second is the file argument.


3 Answers

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.

like image 157
abbot Avatar answered Oct 13 '22 22:10

abbot


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')
like image 37
Schof Avatar answered Oct 13 '22 22:10

Schof


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.

like image 3
Mark Rushakoff Avatar answered Oct 13 '22 22:10

Mark Rushakoff