一個目錄下有很多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