5

我试图用 FIFO 做一些简单的事情:读取行,但不是一次全部读取,而且它出乎意料地“不起作用”。

还行吧:

$ f=$(mktemp -u)
$ mkfifo $f
$ { seq 5 > $f; } &
[1] 2486
$ while read line; do echo $line; done < $f
1
2
3
4
5
[1]+  Done                    { seq 10 > $f; }

但如果我尝试逐行读取,第一次读取成功,第二次读取挂起。

$ { seq 5 > $f; } &
[1] 2527
$ read line < $f; echo $line
1
[1]+  Done                    { seq 5 > $f; }
$ read line < $f; echo $line
[hangs here...]

有人可以解释一下吗?为什么我不能一个接一个地阅读所有 5 行?剩下的数据怎么了?


我发现如果我创建一个文件描述符来重定向 FIFO,我可以逐行读取:

$ { seq 5 > $f; } &
[1] 2732
$ exec 3<$f
[1]+  Done                    { seq 5 > $f; }
$ read -u 3 line && echo $line || echo no more data
1
$ read -u 3 line && echo $line || echo no more data
2
$ read -u 3 line && echo $line || echo no more data
3
$ read -u 3 line && echo $line || echo no more data
4
$ read -u 3 line && echo $line || echo no more data
5
$ read -u 3 line && echo $line || echo no more data
no more data
$ exec 3<&-

我仍然不明白中间的情况。谁能解释一下?


版本信息:

$ bash --version
GNU bash, version 4.2.25(1)-release (i686-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ mkfifo --version
mkfifo (GNU coreutils) 8.13
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David MacKenzie.
4

2 回答 2

6

我猜会发生什么:

$ read line < $f打开 FIFO 进行读取,读取一行,然后关闭 FIFO。一旦读取器关闭其一侧的 FIFO,写入器 ( seq 5 > $f) 也会关闭。当您下次打开 FIFO 时,此时没有人写入它,所以read阻塞。

在命令完成while之前,FIFO 会打开以供读取while,从而允许写入器向 FIFO 发送更多行。

您可以使用lsof -p $$来验证在每个点打开(未)哪些文件。

于 2014-04-15T16:16:18.353 回答
2

似乎这里有些混乱FIFO

当你说:

read line < $f

它会打开FIFO,寻找,读取,并在关闭后完成。无论您是读取一行数据还是读取整个数据都没有关系。

因此,当您尝试再次阅读时,会read一直等待。

在它等待的时候,试着说:

echo foo > $f

你会注意到这read是成功的。

如果您正在监视在这两种情况下进行的系统调用,您会观察到第二个read正在等待从 FIFO 中读取。

不确定您要在这里完成什么,但您的观察几乎符合预期。

于 2014-04-15T16:19:07.510 回答