奇怪的管道缓冲

时间:2019-03-21 09:18:30

标签: bash unix pipe file-descriptor

我的文件充满了文件号(从0开始)

$ cat in.del
0
1
2
....

有人可以解释这里发生了什么以及缓冲在管道中何处发生?据我了解,两个head's fileno(stdin)都必须直接查看管道的读取端

$ cat in.del | ( head -n1 ; head -n1 )
0
60

以下代码与上面的代码有何不同?

$ cat in.del | ( head -n10 ; head -n10 )
0
1
...
8
9
60
1861 # O_o
1862
1863
...
1868
1869

这可以按预期工作,并且表明head本身读取的字节数不超过其实际写入其stdout的字节数:

$ ( head -n10 ; head -n10 ) < ./in.del
0
1
...
9
10
11
...
18
19

很显然,这与发生管道有关

更新

OS:Ubuntu 18.04.1 LTS

Bash:版本4.4.19(1)-发行版(x86_64-pc-linux-gnu)

更新2 除了@Barmar的出色答案之外,more on stdio buffering

1 个答案:

答案 0 :(得分:4)

正在发生的事情是stdio一次从管道读取了整个缓冲区,而Linux上的缓冲区大小为8K。

然后dbleon1从缓冲区中读取前10行,将其打印并退出。

下一个head从最后一个中断的管道开始读取,该管道中有8K字节。它读取该行以及随后的9行。您看到的head60的结尾。

在最后一种情况下按预期方式工作的原因是因为1860在退出前一直搜索到它所打印的最后一行的末尾。寻找在管道中不起作用,因此这没有效果。但是,当head是普通文件时,查找将起作用,并且下一个过程将从查找设置文件位置的地方开始。

我在Mac上看到的结果略有不同。它的缓冲区大小为64K,因此第二个stdin从文件的后面开始。在退出之前,它也不会搜索到最后一个打印行的末尾,因此带有文件重定向的版本与管道相同。