以下均为Linux环境测试。
起因:
开发的一个程序,经常会由于内存不足而被kill掉,使用的是os.system函数执行的,返回值总是35072,当时没多想。后来由于一些原因,要模拟OOM 被kill的状态,于是调用 sys.exit(35072) 突然发现,返回值不对。。。 于是有了下面的。
python中执行系统命令的方式一般来说有两种,os和subprocess(推荐)。
简单用法如下:
import os os.system("ls") # or import subprocess subprocess.call(["ls"])
本文重点在于此两种方式的返回值差异问题。
一、os.system
此函数返回值即为 os.wait 函数返回值中的 exit status,查看官方文档对 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
os.wait 返回一个元组,包含进程id和进程退出状态码。
敲重点:
进程退出码由两部分组成,分别是进程被kill的信号值和进程的退出码。
这两个数字合并为一个16位的数字,前8位是退出码,后8位是kill信号。
10进制计算方式:
进程退出码 = 进程退出码 * 2 ** 8 + kill信号值
测试:
python中可以调用sys.exit或者os._exit来模拟各种退出码
import os cmd = "python -c 'import sys;sys.exit(1)'" r = os.system(cmd) print(r) # r = 256
由于没有被kill,故kill信号值为0,所以 r = 1 * 2 ** 8 + 0 = 256
当进程被kill时,则没有退出码,故 r = kill信号值
tips:
使用 os.WEXITSTATUS 可将 os.system 返回值还原为退出码
二、subprocess.call
此函数返回的是subprocess.Popen对象的returncode属性,这个没找到文档,直接看源码吧。
def _handle_exitstatus( self, sts, _WIFSIGNALED=os.WIFSIGNALED, _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED, _WEXITSTATUS=os.WEXITSTATUS, _WIFSTOPPED=os.WIFSTOPPED, _WSTOPSIG=os.WSTOPSIG, ): """All callers to this function MUST hold self._waitpid_lock.""" # This method is called (indirectly) by __del__, so it cannot # refer to anything outside of its local scope. if _WIFSIGNALED(sts): self.returncode = -_WTERMSIG(sts) elif _WIFEXITED(sts): self.returncode = _WEXITSTATUS(sts) elif _WIFSTOPPED(sts): self.returncode = -_WSTOPSIG(sts) else: # Should never happen raise SubprocessError("Unknown child exit status!")
在源码中可发现,它对不同类型的退出码(或者叫退出码不太合适。。)做了判断,如果是被kill或被停止,则返回一个负值,如果是正常退出码,则原样返回。
测试:
import subprocess r = subprocess.call(["python", "-c", "import sys;sys.exit(1)"]) print(r) # r=1
在没有被kill时,r = 退出码 = 1
当被kill时,懒得写代码了,返回值是 -9、-15等
ps:
Linux errno 的详细说明可参见:
补充一个:
errno: 137 OOM killer
参考文献:
https://docs.python.org/3.7/library/subprocess.html#subprocess.Popen.wait