How to bypass the 0-255 range limit for sys.exit()

2019-03-20 03:06发布

问题:

In python (on a Linux system), I'm launching a command using os.system() and retrieving the return code. If that return code is different from 0, I would like to make the program exit with that same return code. So I wrote:

ret = os.system(cmd)
if ret != 0:
   print "exit with status %s" % ret
   sys.exit(ret)

When the return code is lower than 256, it works fine, but when it's greater than 255, the exit code used is 0. How can I make sys.exit() accept codes greater than 255?

Edit: the limit is actually 255

In fact, the ret variable receives 256, but sys.exit() fails to use it, so the program returns 0 instead. When I launch cmd manually, I see that it returns 1, not 256.

回答1:

Works for me (CentOS 5.5, Python 2.6.5):

$ python
>>> import sys
>>> sys.exit(245)
$ echo $?
245


回答2:

Actually, the documentation indicates that

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.

So I need to process the number returned by sys.exit() in order to retrieve the real exit status, like so:

ret = os.system(cmd)
# Ignore the first byte, use the second one only
ret = ret >> 8
if ret != 0:
   print "exit with status %s" % ret
   sys.exit(ret)

And now it works: ret contains 1 instead of 256.



回答3:

You can't shouldn't, because the system reserves exit codes above 128 for itself. If the return code is from 0 to 127, it means that the program exited by itself. If the return code is higher than 128, it means that the program was terminated by a system signal (e.g. SIGKILL or SIGTERM). The signal number is the result code minus 128.

You'll need to detect it and make some other kind of output indication, I think. Perhaps print the return code to STDOUT and then return with either 0 (normal exit, normal output) or 1 (cmd had a non-zero return value, output means something).

edit: Apparently (from this comment), Python is more clever than a shell script... To put it back into a regular Linux exit code, try this:

subprocess_exit_code = (ret >> 8) & 0x7f
subprocess_signal_number = ret & 0xff

if subpprocess_signal_number == 0:
  exit_code = subprocess_exit_code
else:
  exit_code = 128 + subprocess_signal_number

Although this ignores the core-dump information.