4

小议bash中的COPROC

 2 years ago
source link: https://www.lujun9972.win/blog/2018/04/26/%E5%B0%8F%E8%AE%AEbash%E4%B8%AD%E7%9A%84coproc/index.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

小议bash中的COPROC

在bash中,两个进程之间要传输数据的最常见方法就是用匿名管道了,像这样

commandA|commandB|commandC

但是使用匿名管道最大的一个问题是,数据的传输是单向的,即commandB只能从commandA的输出中读取数据,然后commandB的输出只能被commandC读取。

那么若想要两个进程之间相互读取数据怎么办呢?也就是说我希望上面的commandA和commandC其实是同一个进程怎么办? 一个常见的解决方法就是使用命名管道:

mkfifo in out
trap 'rm in out' EXIT
cmd <in >out &
exec 3> in 4< out
echo $data >&3
read $data <&4

不过使用命名管道也有一个麻烦事,就是需要记得清理生成的管道文件。

不过,自bash4.0开始,bash引入了一个关键字 coproc, 用来在后台创建一个协作进程(co-process), 同时将它的输入和输出通过管道与文件句柄相连。

有点类似于C中的 FILE * popen ( const char * command , const char * type ); 函数,只不过它同时产生输入和输出两个句柄。

COPROC语法

根据bash manual的说法,coprocess的语法为

coproc [NAME] command [redirections]

其中当command为简单命令时,不能有 NAME.

这个说法很容易让人感到困惑,什么叫简单命令?这个概念不直观。

直观点说,可以认为 coproc 有两类用法,一类是基本语法,一类是扩展的语法。

COPROC基本语法

COPROC的基本语法适用于当只需要有一个coprocess的情况,它的语法为

coproc cmd [redirections]

这时与coprocess的输入/输出管道相连的句柄保存在 $COPROC 数组中,分别为 ${COPROC[1]}${COPROC[0]}

因此,你可以使用 echo $data >&"${COPROC[1]}" 来往coprocess中输入数据, 通过使用 echo $data <&"${COPROC[0]}" 来读取coprocess的输出数据。

COPROC的扩展语法

当需要创建多个coprocess时,你就需要使用coproc的扩展语法了,因为它允许你为coprocess命名。

coproc NAME {cmds} [redirections]

有没有觉得它跟bash中定义函数的语法 function NAME {cmds} 很类似?

这时与coprocess的输入/输出管道相连的句柄保存在 $NAME 数组中,分别为 ${NAME[1]}${NAME[0]}

对应的,你可以使用 echo $data >&"${NAME[1]}" 来往coprocess中输入数据, 通过使用 echo $data <&"${NAME[0]}" 来读取coprocess的输出数据。

关闭不需要的管道

若coprocess只需要输入句柄或输出句柄,则可以使用 exec 来关闭不需要的文件句柄

exec {NAME[0]}>&-
exec {NAME[1]}>&-

使用coprocess虽然方便,但要当心coprocess由于输出缓存而导致的卡死。

比如下面这个例子

coproc tr a b
echo a >&"${COPROC[1]}"
read var<&"${COPROC[0]}"

你的期望是第三句能够读出字符 b 作为 var 的值, 然而实际上执行到第三句话时会卡死。 这是因为 tr 命令缓存了输出的内容,而并未将其写到终端上来。

因此创建coprocess时一定小心,只能使用那些不会缓存输出的命令。 也正因为此,coprocess的使用范围其实也很受限,真要用来跟其他进程做交互的话,还是推荐使用 expert 比较好。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK