检索协同处理的输出和退出代码

时间:2019-09-10 19:58:04

标签: bash shell io-redirection

我必须在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展开$COPROC来表示51,则此更改应表示“使stdin此过程的 FD 51中读取的信息流”;
  2. coproccat命令之间调用命令会使命令在协同处理结束时失败,并给出错误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如何获得协同处理的输出。

P.S:测试是在交互式外壳中完成的。

1 个答案:

答案 0 :(得分:3)

  

cat <&$COPROC

     

因此,如果bash将$COPROC扩展为51,则此更改应表示“从该进程的FD 51的流中读取标准输入”;

否,这意味着:派生一个单独的进程(将从父进程中继承所有打开的fds,并对其进行继承),使fd 0(stdin)成为fd 51(dup2(51, 0)的别名, <&会执行此操作,然后执行cat,这将再次继承所有打开的fds(包括stdin = 0),除了标有O_CLOEXEC的那些(我$COPROC = 51)。

请注意,$COPROC实际上是一个数组:在bash中将数组用作简单变量将检索其第一个元素:$COPROC${COPROC[0]}相同,即它的阅读结束。

  

sleepcoproc命令之间放置cat命令会使后者失败,从而导致错误重击:$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并不总是可靠的原因-在您使用它们时,它们可能已经被重新用于其他过程。

相关问题