为什么
import subprocess
p = subprocess.Popen(["/bin/bash", "-c", "timeout -s KILL 1 sleep 5 2>/dev/null"])
p.wait()
print(p.returncode)
返回
[stderr:] /bin/bash: line 1: 963663 Killed timeout -s KILL 1 sleep 5 2> /dev/null
[stdout:] 137
当
import subprocess
p = subprocess.Popen(["/bin/bash", "-c", "timeout -s KILL 1 sleep 5"])
p.wait()
print(p.returncode)
返回
[stdout:] -9
如果将bash更改为破折号,则两种情况下都会获得137。我知道-9是KILL代码而137是128 + 9.但类似的代码看起来很奇怪,以获得不同的返回码。
发生在Python 2.7.12和python 3.4.3
上在使用Popen.wait()
时,Popen._handle_exitstatus
似乎没有调用/bin/bash
https://github.com/python/cpython/blob/3.4/Lib/subprocess.py#L1468,但我无法弄清楚原因。
答案 0 :(得分:4)
这是因为bash
如何在有或没有重定向/管道或任何其他bash功能的情况下执行timeout
:
使用重定向
python
启动bash
bash
启动timeout
,监控流程并进行管道处理。timeout
将自己转移到新的流程组并启动sleep
timeout
将SIGKILL
发送到其流程组bash
从等待timeout
返回,看到SIGKILL
并将上面粘贴的消息打印到stderr
。然后,它将自己的退出状态设置为128 + 9(由timeout
模拟的行为)。没有重定向
python
启动bash
。bash
发现它本身无关,并致电execve()
以有效地将自己替换为timeout
。timeout
如上所示,整个流程组以SIGKILL
而死。python
退出状态为9
并进行一些修改以将其转换为-9
(SIGKILL
)换句话说,没有重定向/管道/等。 bash
退出了呼叫链。您的第二个示例看起来subprocess.Popen()
正在执行bash
,但实际上并非如此。当bash
履行契约时,timeout
已不再存在,这就是为什么您不会收到任何消息和无法退出的退出状态。
如果您想要一致的行为,请使用timeout --foreground
;在这两种情况下,你都会获得124的退出状态。
我不知道冲刺;但是假设它没有做任何execve()
诡计来有效地用它执行的唯一程序替换自己。因此,您总是会看到破折号的退出状态为128 + 9。
更新:zsh
显示相同的行为,即使对于timeout -s KILL 1 sleep 5 >/tmp/foo
之类的简单重定向,它也会退出,退出状态为-9。 timeout -s KILL 1 sleep 5 && echo $?
也会在zsh
中为您提供状态137。