首页 > 解决方案 > 检索协同进程的输出和退出代码

问题描述

我必须在bash. 所以我最终得到了以下结果,但奇怪的是,我不知道它为什么会起作用:

coproc { sleep 30 && echo "Output" && exit 3; }
# Saving the coprocess's PID for later, as COPROC_PID apparently unsets when its finished
COPROC_PID_backup=$COPROC_PID

# Retrieving the coprocess's output
output=$(cat <&$COPROC)

# Retrieving the coprocess's exit code
wait $COPROC_PID_backup

# Echoing out the results
echo $?
echo $output

我“成功”得到以下输出:

3
Output

这里有很多我不明白的事情:

  1. 如何cat从该文件描述符中读取协同进程的输出?我认为这些取决于过程。因此,如果bash扩展$COPROC51,那么这个改写应该意味着“stdin这个进程的 FD 51流中读取”;
  2. coproc如果协同进程结束,则在和命令之间调用cat命令会使后者失败,并给出错误bash: $COPROC : ambiguous redirection,例如,如果我使用 while 循环等待:
coproc { sleep 30 && echo "Output" && exit 3; }

while kill -0 $COPROC_PID_backup &>/dev/null ; do
    sleep 1
done

output=$(cat <&$COPROC) # Fails
  1. 如何wait获取协同进程的退出代码,因为它已经结束。被存储直到它被读取一次?如果有,在哪里?

我一定误解了重定向是如何工作的,因为我真的不明白如何cat能够获得协同进程的输出。

PS:测试是在交互式外壳中完成的。

标签: bashshellio-redirection

解决方案


cat <&$COPROC

因此,如果 bash 扩展$COPROC51,那么这个改写应该意味着“从这个进程的 FD 51 的流中读取标准输入”;

不,这意味着:fork 一个单独的进程(它将从其父进程继承dup2(51, 0)所有打开的 fds),使 fd 0(stdin)成为 fd 51 的别名(就是这样<&做的)然后 exec cat,它将再次继承所有打开的 fds(包括stdin = 0),除了那些标有O_CLOEXEC(我敢打赌$COPROC= 51的情况)。

注意它$COPROC实际上是一个数组:使用数组作为简单变量 inbash将检索它的第一个元素:$COPROC与 相同${COPROC[0]},即它的读取端。

在和命令sleep之间放置一个命令会使后者失败,并给出错误 bash: ;coproccat$COPROC : ambiguous redirection

bash$COPROC一旦协进程终止,将取消设置变量(或任何协进程名称)。所以cat <&$COPROC会产生与cat <&$no_such_variable. 例子:

$ coproc foo { true; }; sleep 1; echo foo=$foo; true <&$foo
[5] 4658
[5]   Done                    coproc foo { true; }
foo=
bash: $foo: ambiguous redirect
$ coproc foo { sleep 2; }; sleep 1; echo foo=$foo; true <&$foo
[5] 4664
foo=61

在第二种情况下,协同进程将比sleep 1.

如何wait获取协同进程的退出代码,因为它已经结束。被存储直到它被读取一次?如果有,在哪里?

bash将自称为wait(2)waitpid(2)类似的系统调用,并将子进程的状态存储在其内存中的某个位置。请注意,bash 正在贪婪地等待它的孩子;在脚本关心它们之前,它不会留下僵尸进程wait(正如一些评论所暗示的那样)。这就是为什么$!或者您$COPROC_PID_backup并不总是可靠的原因——当您使用它们时,它们可能已经被重用于另一个进程。


推荐阅读