为什么
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 更改为 dash,在这两种情况下都会得到 137。我知道 -9 是 KILL 代码而 137 是 128 + 9。但是对于类似的代码获得不同的返回码似乎很奇怪。
出现在 Python 2.7.12 和 python 3.4.3
看起来 Popen.wait()
没有调用 Popen._handle_exitstatus
https://github.com/python/cpython/blob/3.4/Lib/subprocess.py#L1468当使用 /bin/bash
但我不知道为什么。
最佳答案
这是因为 bash
执行 timeout
有或没有重定向/管道或任何其他 bash 功能:
带重定向
-
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还有。
关于python - 为什么 subprocess.Popen 返回码与 bash 的类似命令不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45824955/