bash coproc和剩余的coproc输出

时间:2011-10-04 17:48:04

标签: bash coproc

我需要在bash脚本中将一些配置数据读入环境变量。

“明显的”(但不正确)模式是:

egrep "pattern" config-file.cfg | read VAR1 VAR2 VAR3 etc...

这会失败,因为read在子shell中运行,因此无法在调用shell中设置变量。所以我想出了这个作为替代

coproc egrep "pattern" config-file.cfg
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc...

工作正常。

为了测试如果协同进程返回多行会发生什么,我尝试了这个:

coproc cat config-file.cfg
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc...

其中config-file.cfg包含三行。

$ cat config-file.cfg
LINE1 A1 B1 C1
LINE2 A2 B2 C2
LINE3 A3 B3 C3

我希望这会处理文件中的第一行,然后是某种“破管”错误消息。当 处理第一行时,没有错误消息,也没有任何协同进程继续运行。

然后我在脚本中尝试了以下内容:

$ cat test.sh
coproc cat config-file.cfg
read -u ${COPROC[0]} VAR1 VAR2 VAR3 VAR4
echo $VAR1 $VAR2 $VAR3 $VAR4
wait
echo $?

运行它:

$ bash -x test.sh
+ read -u 63 VAR1 VAR2 VAR3 VAR4
+ cat config-file.cfg
LINE1 A1 B1 C1
+ wait
+ echo 0
0

剩下的两条线去了哪里?我原本期望“断管”或wait挂起,因为没有什么东西可以读取其余的行,但正如你所看到的那样,返回代码为零。

3 个答案:

答案 0 :(得分:6)

根据上述评论,您可以使用process substitution来实现这一目标。这样,read不会在子shell中运行,捕获的变量将在当前shell中可用。

read VAR1 VAR2 VAR3 < <(egrep "pattern" config-file.cfg)

  

“如果使用&lt;(list)表单,则应该读取作为参数传递的文件以获取列表的输出” - 作为ag​​rument传递的“什么”文件“他们在谈论什么?

这对我来说也很神秘。高级Bash脚本指南中的chapter on process substitution有更全面的解释。

我看到它的方式,当使用<(cmd)语法时,cmd的输出通过命名管道(或临时文件)提供,语法被替换为文件名管/文件。因此,对于上面的示例,它最终将等同于:

read VAR1 VAR2 VAR3 < /dev/fd/63

其中/dev/fd/63是连接到cmd标准输出的命名管道。

答案 1 :(得分:2)

如果我理解你的问题(我希望我没说明显的话), read 一次读取一行,如:

$ read a b c < config-file.cfg && echo $?
0

或:

$ printf '%s\n%s\n' one two | { read; echo "$REPLY";}
one

$ echo ${PIPESTATUS[@]}
0 0

要阅读所有输入,您需要一个循环:

$ coproc cat config-file.cfg
[1] 3460

$ while read -u ${COPROC[0]} VAR1 VAR2 VAR3; do echo $VAR1 $VAR2 $VAR3; done
LINE1 A1 B1 C1
LINE2 A2 B2 C2
LINE3 A3 B3 C3
[1]+  Done                    coproc COPROC cat config-file.cfg

只需补充说明FAQ

中对此进行了解释

答案 2 :(得分:1)

发生的情况是,一旦子外壳程序完成,父外壳程序便会清理并关闭FD。您很幸运,您甚至必须阅读第一行!

在交互式外壳中尝试:

$ coproc ECHO { echo foo; echo bar; }
[2] 16472
[2]+  Done                    coproc ECHO { echo foo; echo bar; }
$ read -u ${ECHO[0]}; echo $REPLY
bash: read: -u: option requires an argument
read: usage: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

它甚至清除环境变量。

现在尝试:

$ coproc ECHO { echo foo; echo bar; sleep 30; }
[2] 16485
$ read -u ${ECHO[0]}; echo $REPLY
foo
$ read -u ${ECHO[0]}; echo $REPLY
bar
$ read -u ${ECHO[0]}; echo $REPLY # blocks until the 30 seconds are up

[2]+  Done                    coproc ECHO { echo foo; echo bar; sleep 30; }

对于解决问题背后的问题:是的,对于给定的特定示例,重定向和流程替换是更好的选择。