一个目录下有很多txt文件。
如果我time wc -l *.txt | head
这样做需要
real 0m0.032s
user 0m0.020s
sys 0m0.008s
如果我time wc -l *.txt | tail
这样做需要
real 0m0.156s
user 0m0.076s
sys 0m0.088s
这是否意味着wc
会事先知道它正在通过管道传输到头部并且仅计算前 10 个文件并节省时间?换句话说,它知道管道吗?这是有什么特别之处wc
还是适用于所有标准/内置命令?
答案1
我strace
对这两个命令都做了 a 。有趣的是,当你通过管道输出时,head
只有 123 个系统调用。另一方面,当通过管道传输到 tail 时,有 245 个系统调用(或者当有更多 *.txt 文件时更多)。
案例:头部
以下是通过管道传输到 时的最后几行head
:
open("file12.txt", O_RDONLY) = 3
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "", 16384) = 0
write(1, "0 file12.txt\n", 13) = -1 EPIPE (Broken pipe)
--- SIGPIPE (Broken pipe) @ 0 (0) ---
+++ killed by SIGPIPE +++
当wc
尝试写入第 12 个文件的输出时,会出现错误EPIPE
。这就是为什么head
在得到第11行后退出的原因。退出时head
,wc
得到SIGPIPE
.如上面的 strace 输出所示,wc
首先尝试写入该管道(head
不再从中读取)并收到管道已损坏的错误。
当进程尝试写入另一端未连接进程的管道时,会向进程发送 SIGPIPE 信号。 - 从维基百科
案例:尾部
当通过管道传输到 时tail
,没有与上面类似的情况。在将所有输出写入tail
需要一直连接的管道后,wc 优雅地结束。tail
需要所有行才能打印最后 10 行。当没有更多输出可供读取时,tail
也打印行并优雅退出
答案2
如果任何不阻塞的进程SIGPIPE
的输出到达无人读取的管道的写入端,则该进程将被终止。
因此,一旦head
关闭其输入(即终止),wc
就会死亡,这比完成所有工作花费的时间更少。
答案3
你可以这样做来消失你的文件:
time wc -l *.txt > tee | tail
但是您为 tee 命令添加了一点时间time
。
和tee command
:
root@debian:/home/mohsen/test# time wc -l *.txt > tee | tail
real 0m0.005s
user 0m0.000s
sys 0m0.000s
没有tee command
:
root@debian:/home/mohsen/test# time wc -l *.txt | tail
8 f3.txt
7 fi.txt
5 mydata.txt
4 newfile.txt
4 t1.txt
4 t2.txt
5 test.txt
4 text.txt
0 t.txt
49 total
real 0m0.004s
user 0m0.000s
sys 0m0.000s