bash - 奇怪的管道缓冲

标签 bash unix pipe file-descriptor

我有一个全是文件编号的文件(从0开始)

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

谁能解释这里发生了什么,缓冲发生在管道以外的什么地方?据我了解,head 的 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

显然有一些与管道相关的事情正在发生

更新

操作系统:Ubuntu 18.04.1 LTS

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

更新 2 作为@Barmar 精彩回答的补充,more on stdio buffering

最佳答案

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

然后 head 从缓冲区中读取前 10 行,打印它们,然后退出。

下一个 head 开始从最后一个停止的管道读取 8K 字节到文件中。它读取该行和以下 9 行。您看到的 601860 的结尾。

在最后一个例子中它按预期工作的原因是因为 head 在它退出之前寻找到它打印的最后一行的末尾。搜索在管道中不起作用,所以这没有效果。但是当stdin是普通文件时,seek起作用,下一个过程从seek设置文件位置的地方开始。

我在 Mac 上看到的结果略有不同。它的缓冲区大小为 64K,因此第二个 head 在文件中开始得晚得多。它在退出之前也不会返回到最后打印行的末尾,因此具有文件重定向的版本与管道一样工作。

关于bash - 奇怪的管道缓冲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55277093/

相关文章:

java - 使用 CURL 将表单数据发布到网页

c - 如何存储每个进程变量,类似于 unix 如何存储每个进程的 pwd?

java - 从 Apache Commons-Exec 捕获大量输出

c++ - 父进程如何用一个管道向 n 个子进程发送消息?

将进出管道连接到网络套接字

python - 如何在 python 中运行这个 shell 脚本?

从 bash 运行的 python 多行命令

python - 如何在 python 脚本中调用 sed 命令?

python - 在 Python 中调用 sar 会产生奇怪的结果

linux - 在脚本中使用 inotify 监控目录