我必须在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
有很多我在这里不明白的事情:
cat
如何从该文件描述符读取协同处理的输出?我认为这些是过程依赖的。因此,如果bash
展开$COPROC
来表示51
,则此更改应表示“使stdin
从此过程的 FD 51
中读取的信息流”; 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
wait
如何能够获取协过程的退出代码,因为它已经结束了。是否存储到读取一次?如果是这样,在哪里?我一定误会了重定向的工作原理,因为我真的不了解cat
如何获得协同处理的输出。
P.S:测试是在交互式外壳中完成的。
答案 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]}
相同,即它的阅读结束。
在
sleep
和coproc
命令之间放置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
并不总是可靠的原因-在您使用它们时,它们可能已经被重新用于其他过程。