如何使用 tee 重定向到 grep
我沒有太多使用 tee 的經驗,所以我希望這不是很基礎。
在查看了這個問題的一個答案後,我遇到了一種奇怪的行為
tee
。為了讓我輸出第一行和找到的行,我可以使用這個:
ps aux | tee >(head -n1) | grep syslog USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
但是,我第一次執行這個(在 zsh 中)時,結果順序錯誤,列標題在 grep 結果下方(但是這沒有再次發生),所以我嘗試交換命令:
ps aux | tee >(grep syslog) | head -n1 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
只列印第一行,沒有其他內容!我可以使用 tee 重定向到 grep,還是我以錯誤的方式執行此操作?
當我輸入這個問題時,第二個命令實際上為我工作了一次,我又執行了五次,然後返回到單行結果。這只是我的系統嗎?(我在 tmux 中執行 zsh)。
最後,為什麼第一個命令沒有顯示“grep syslog”作為結果(只有一個結果)?
這裡的控制是沒有 grep
tee
ps aux | grep syslog syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4 henry 2290 0.0 0.1 95220 3092 ? Ssl Sep07 3:12 /usr/bin/pulseaudio --start --log-target=syslog henry 15924 0.0 0.0 3128 824 pts/4 S+ 13:44 0:00 grep syslog
更新: 似乎 head 導致整個命令被截斷(如下面的答案所示),下面的命令現在返回以下內容:
ps aux | tee >(grep syslog) | head -n1 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND syslog 806
$ ps aux | tee >(head -n1) | grep syslog USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
和命令大約在同一時間開始,
grep
並且head
兩者都在空閒時接收相同的輸入數據,但通常是在數據可用時。有些事情會引入翻轉線路的“不同步”輸出;例如:
- 多路復用的數據
tee
實際上先於一個程序發送到另一個程序,這主要取決於tee
. 一個簡單的tee
實現將read
輸入一些輸入,然後輸入write
兩次:一次到標準輸出,一次到它的參數。這意味著其中一個目的地將首先獲取數據。但是,管道都是緩衝的。這些緩衝區很可能每個為 1 行,但它們可能更大,這可能導致其中一個接收命令在
grep
另一個命令(head
全部。 2. 儘管如此,也有可能這些命令之一接收到數據但無法及時對其進行任何處理,然後另一個命令接收到更多數據并快速處理它。例如,即使一次發送
head
一行grep
數據,如果head
不知道如何處理它(或被核心調度延遲),甚至可以在有機會grep
之前顯示其結果。head
為了展示,嘗試添加延遲:ps aux | tee >(sleep 1; head -n1) | grep syslog
這幾乎肯定會grep
首先輸出輸出。$ ps aux | tee >(grep syslog) | head -n1 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
我相信你經常在這裡只得到一行,因為
head
接收到第一行輸入然後關閉它的標準輸入並退出。當tee
看到其標準輸出已關閉時,它會關閉自己的標準輸入(來自 的輸出ps
)並退出。這可能取決於實現。實際上,唯一
ps
要發送的數據是第一行(當然,因為head
正在控制它),可能還有其他一些行,然後head
關閉tee
它們的標準輸入描述符。第二行是否出現的不一致是定時引入的:
head
關閉stdin,但ps
仍在發送數據。這兩個事件沒有很好地同步,因此包含的行syslog
仍然有機會使其成為tee
的參數(grep
命令)。這與上面的解釋類似。您可以通過使用在關閉標準輸入/退出之前等待所有輸入的命令來完全避免這個問題。例如,使用
awk
代替head
,它將讀取並處理其所有行(即使它們不會導致輸出):ps aux | tee >(grep syslog) | awk 'NR == 1'
但請注意,這些行仍然可能出現亂序,如上所示,可以通過以下方式證明:
ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1')
希望這不是太多細節,但是有很多同時發生的事情相互作用。單獨的程序同時執行而沒有任何同步,因此它們在任何特定執行上的操作都可能有所不同;有時深入探勘底層過程來解釋原因會有所幫助。