等待管道中的进程返回错误的退出代码

等待管道中的进程返回错误的退出代码

我一定在这里遗漏了一些东西:

#!/bin/bash
timeout 5 sleep 10 &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"

调用脚本wait-pid并运行:

$ ./wait-pid 
exit code: 124

这是我所期望的,timeout杀死sleep进程并以 124 退出,它wait会尽职地返回。

但是如果我向初始命令添加管道:

timeout 5 sleep 10 | cat &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"

现在我得到:

$ ./wait-pid 
exit code: 0

不应该wait仍然返回它正在等待的进程的退出代码:timeout。那么退出代码不应该仍然是 124 吗?

这是 bash 4.4.20(1)-release 的版本。

答案1

我在 bash 邮件列表上收到了来自知识渊博的 Greg Wooledge 的答复。关键要素是:

wait 命令仅适用于 shell 的直接子进程,也称为“异步命令”。如果您的异步命令是管道,我们将回退到原始的 sh 功能集。异步命令的退出状态是管道中最后一个命令的退出状态,其他命令的退出状态将被简单地丢弃。

所以这就是为什么我没有得到timeout它在管道中时的退出代码。

获得我想要的行为的方法是使用临时文件从异步代码中捕获退出代码。就像是:

{
  timeout 5 sleep 10 | cat
  echo "${PIPESTATUS[@]}" > "$tempfile"
} &
wait

相关内容