我正在尝试使用bashcoproc
,但遇到了困难,很可能是缓冲问题。我有一个复杂的命令,它接受来自stdin的面向行的输入,并在每行输入中将一行打印到stdout。在命令行中,该命令每行运行良好,但当我将其放入协处理器并从${COPROC[0]}
FD读取时,读取会阻塞。
我可以用paste
重新创建这种行为,但不能用cat
。我希望paste
和cat
在不传递参数的情况下能做同样的事情。直接在命令提示符下运行时会出现这种情况:
$ cat
Hello World!<RETURN>
Hello World!^D
$ paste
Hello World!<RETURN>
Hello World!^D
$
(添加RETURN
和^D
以供说明)
但当我把它们放在一个协处理器中时,它们的行为就不同了——cat
是严格的行缓冲的,而paste
似乎是用一个更大的缓冲区操作的:
$ coproc cat
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
Hello world!
$ kill $COPROC_PID
[3]+ Terminated coproc COPROC cat
$
$ coproc paste
[3] 42657
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
#### read blocks here until ^C ####
我认为这是因为paste
根据其连接的内容调整其缓冲模式,而cat
始终处于行缓冲模式。
是否有任何方法可以强制paste
(或其他通用命令)在协处理器中进行行缓冲?
经过更多的实验,我发现我可以在没有协处理器的情况下重新创建类似的行为,而只是在cat
和paste
:之间进行管道传输
$ cat | cat
Hello World!<RETURN>
Hello World!^D
$ cat | paste
Hello World!<RETURN>
Hello World!^D
$ paste | cat
Hello World!<RETURN>
#### command blocks here until ^C ####
(添加RETURN
和^D
以供说明)
- 首先,我们将
cat
管道传输到cat
,并一直获得行缓冲 - 接下来,我们将
cat
管道传输到paste
,并始终获得行缓冲 - 最后,我们将
paste
管道传输到cat
,并且不获得行缓冲
这似乎表明paste
在交互模式下将对其stdout进行行缓冲,但除此之外,它将使用更大的缓冲区。
强制行缓冲的一种方法是使用stdbuf
coreutils工具(如果可用):
stdbuf
允许修改与程序相关联的三个标准I/O流的缓冲操作。
对于coproc
情况:
$ coproc stdbuf -oL paste
[3] 42751
$ echo 'Hello world!' >&${COPROC[1]}
$ read -ru ${COPROC[0]} line; echo $line
Hello world!
$ kill $COPROC_PID
[3]+ Terminated coproc COPROC stdbuf -oL paste
$
对于paste
到cat
的简单管道情况:
$ stdbuf -oL paste | cat
Hello World!<RETURN>
Hello World!^D
$