![三重管道到 STDOUT & tee /dev/null >(wc -l > tmp.txt) 的奇怪结果 & 再次管道嵌入 `cat tmp.txt`](https://linux22.com/image/100711/%E4%B8%89%E9%87%8D%E7%AE%A1%E9%81%93%E5%88%B0%20STDOUT%20%26%20tee%20%2Fdev%2Fnull%20%3E(wc%20-l%20%3E%20tmp.txt)%20%E7%9A%84%E5%A5%87%E6%80%AA%E7%BB%93%E6%9E%9C%20%26%20%E5%86%8D%E6%AC%A1%E7%AE%A1%E9%81%93%E5%B5%8C%E5%85%A5%20%60cat%20tmp.txt%60.png)
$ seq 1 12773 | tee /dev/null >(wc -l > tmp.txt) | head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1
--> 8473 (1~12773之间随机)
$ cat tmp.txt
--> 8473
$ seq 1 12774 | tee /dev/null >(wc -l > tmp.txt) | head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1
-->(空)
$ cat tmp.txt
--> 8844 (1~12773之间随机)
$ seq 1 25011 | tee /dev/null >(wc -l > tmp.txt) | cat | head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1
--> 13778 (1~25011之间随机)
$ cat tmp.txt
--> 13778
$ seq 1 25012 | tee /dev/null >(wc -l > tmp.txt) | cat |head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1
-->(空)
$ cat tmp.txt
--> 24939 (1~25012之间随机)
$ seq 1 46014 | tee /dev/null >(wc -l > tmp.txt) | cat | cat |head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1
--> 34111 (1~46014之间随机)
$ cat tmp.txt
--> 34111 (1~46014之间随机)
$ seq 1 46015 | tee /dev/null >(wc -l > tmp.txt) | cat | cat |head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1
-->(空)
$ cat tmp.txt
--> 343 (1~46014之间随机)
作为 '| 的数量cat 后面的“(wc -l > tmp.txt)”增加,您可以使上述命令处理更多的行数。
这是怎么回事?
答案1
作为亚历克斯·P已在评论中解释过,管道中的命令并行运行。你似乎确信事实并非如此;请忘记这个错误观念,只要你不敞开心扉,你就无法理解正在发生的事情。
由于进程是并行运行的,因此操作顺序取决于确切的时间,并且可能无法从一次运行复制到下一次运行。
以第一个示例为例,以下命令并行运行:
seq 1 12773
tee /dev/null
wc -l > tmp.txt
(进程替换还会创建管道并并行运行命令)head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))
— 这涉及三个不同的命令,并head
在两个命令openssl
都cat
退出后启动tail -1
由于wc -l > tmp.txt
和cat tmp.txt
并行运行,因此cat tmp.txt
与以下输出相关的运行时间是不可预测的wc
:
- 它可能会在执行重定向之前运行
tmp.txt
,并且要么从上一次运行中获取文件(如果有),要么抱怨该文件不存在。 - 它可以在执行重定向之后但在
wc
产生任何输出之前运行;在这种情况下,文件为空,因为重定向会截断文件。 - 它可以在
wc
生成输出时运行,并且仅拾取输出的开头。在大多数系统上,wc
自动生成输出(因为它很短),因此不会发生这种情况。 wc
它可以在完成输出后运行。
通过实验,我得到了与您相同的结果(在运行内核 3.16 的 Linux 机器上,该机器在其他情况下大部分处于空闲状态):使用seq 1 12773
,获取;cat tmp.txt
的输出。wc
使用seq 1 12774
,cat tmp.txt
选取一个空文件。那么为什么 12773 和 12774 之间存在差异,但低于该值的结果却相当可靠呢?
$ seq 1 12774 | wc -c
65538
阈值是 65536 字节,该值是管道缓冲区的容量。该head …
命令启动速度很慢,因为它必须先运行openssl
并cat
完成。当它启动时,管道中的前一个命令会写入管道缓冲区。当管道缓冲区已满时,前一个命令必须停止。当数字达到 12773 时,管道缓冲区永远不会填满,因此很可能seq
之前就完成了运行openssl
(它要做的工作少了很多)并且wc
有时间写入其输出。但是当数字大于 12774 时,管道缓冲区就会被填满;所以tee
被困在写入到 的输出中head …
,并且尚未完成将输出写入到wc
。同时,cat
以空文件运行。
tee
当您添加更多管道时,每个管道都有自己的缓冲区,因此在停顿之前有更多空间。