如何在不等待的情况下 cat 命名管道

Ale*_*lls 6 tail cat fifo

如果命名管道中没有任何内容,我会这样做:

cat my_named_pipe
Run Code Online (Sandbox Code Playgroud)

它将等到数据到达。如果没有要读取的数据,是否有可以立即退出的标志?或者也许是我可以使用的 cat 以外的命令?

我也试过:

read val < "$my_named_pipe";
Run Code Online (Sandbox Code Playgroud)

但这也会等待下一个数据块 - 如果 fifo 为空,我不想等待。

Sté*_*las 8

为了防止cat在没有任何作者的情况下挂起(在这种情况下,这是打开 fifo,而不是读取它,挂起),您可以执行以下操作:

cat 0<> "$my_named_pipe" <"$my_named_pipe"
Run Code Online (Sandbox Code Playgroud)

第一个重定向以读+写模式打开,在大多数系统上,即使没有写入器或读取器,也不会阻塞和实例化管道。然后第二个打开(这次是只读的)不会阻塞,因为现在至少有一个写入器(它本身)。

0只需要在ksh93的的最新版本,其中默认为FD<>改为从0到1。

此外,在ksh93,这将不工作的时候cat是shell内建的时候就像ksh93被调用时/opt/ast/bin是超前/bin$PATH或者在通话结束后builtin cat为对<"$my_named_pipe",(我猜)ksh93的保存标准输入上一个单独的文件中描述的先前的目标这将保持管道打开。您可以通过编写它来解决这个问题:

cat 3<> "$my_named_pipe" <"$my_named_pipe" 3<&-
Run Code Online (Sandbox Code Playgroud)

(你也可能认为这更清楚地传达了意图)

请注意,<>管道上的其他读者也会解锁fifo。

如果有一些作家,cat仍然需要读取他们的所有输出并等待他们关闭管道的末端。您可以以非阻塞模式打开管道,就像使用 GNU 一样dd

dd bs=64k if="$my_named_pipe" iflag=nonblock status=noxfer
Run Code Online (Sandbox Code Playgroud)

只要其中有一些数据,它只会从管道中读取,并退出

dd: error reading 'fifo': Resource temporarily unavailable
Run Code Online (Sandbox Code Playgroud)

当没有更多读取器时出错,并且不会解锁其他读取器,但这意味着如果写入管道的速度比您 ( dd) 读取它的速度慢,您可能会错过一些写入器的输出。

另一种方法可能是在一段时间内没有输入时超时,例如使用socat's-T选项:

socat -u -T1 - - 0<> "$my_named_pipe" <"$my_named_pipe"
Run Code Online (Sandbox Code Playgroud)

如果一秒钟内没有任何东西从管道中流出,它将退出。

  • 注意:这个技巧仍然依赖于所有其他作者关闭管道,以便 `cat` 返回。如果另一个进程已经打开了管道,例如。`exec 7&gt;fifo` 并保持 fd 7 打开,`cat &lt;&gt;fifo &lt;fifo` 仍然会阻塞,但不是在尝试打开管道时,而是在尝试从中读取更多数据时。 (2认同)