2017-12-02 135 views
0

運行此:不打印通過兩個命令

ping google.com | grep -o 'PING' 

將打印PING到終端,所以我假定意味着grep的的標準輸出由終端捕獲。

那麼爲什麼不按照下面的命令打印什麼?終端只是掛:

ping google.com | grep -o 'PING' | grep -o 'IN' 

我認爲,第一grep命令的標準輸出將被重定向到第二的grep的標準輸入。然後第二個grep的標準輸出將被終端捕獲並打印。

這似乎是,如果平被替換回聲會發生什麼:

echo 'PING' | grep -o 'PING' | grep -o 'IN' 

IN被打印到終端,如我期望的那樣。

那麼ping有什麼特別之處,可以防止打印任何東西?

+2

瞭解grep的'--line-buffered'選項。它會解決你的問題 – RomanPerekhrest

+0

嘗試'ping -c 5',以便在5次嘗試後停止。 –

+0

@RomanPerekhrest謝謝!但我不確定爲什麼這個選項使它工作或如何推廣解決方案。其他命令也存在這個問題,如perl:'ping google.com | perl -pe''| grep -o'IN'輸出什麼也沒有,並且perl似乎沒有相同的選項。 – Robz

回答

2

你可以嘗試更加耐心:-)

ping google.com | grep -o 'PING' | grep -o 'IN' 

最終顯示輸出,但它可能需要一個半小時左右。

在Unix下,如果流是終端,則在啓動時交給程序的標準輸出流是「行緩衝」的;否則它會被完全緩衝,通常使用8千字節(8,192個字符)的緩衝區。緩衝意味着輸出在內存中累積,直到緩衝區已滿,或者在線路緩衝流的情況下,直到發送換行符爲止。

當然,程序可以覆蓋此設置,只生成少量輸出的程序(如ping)通常會執行stdout行緩衝,而不管它是什麼。但grep不這樣做(雖然你可以告訴牛羚grep來做到這一點通過--line-buffered命令行選項。)

「管道」(其中創建實現|運營商)都沒有考慮終端。因此中間的grep將具有完全緩衝輸出,這意味着其輸出將被緩衝直到寫入8k個字符。這將需要一段時間,因爲每行只包含5個字符(PING加換行符),並且它們每秒生成一次。所以緩衝區將在大約1640秒後填滿,這大約是28分鐘。

很多unix發行版帶有一個名爲stdbuf的程序,它可以用來在運行程序之前更改標準流的緩衝區。 (如果你有stdbuf,你可以通過輸入man 1 stdbuf來了解它是如何工作的。)像Perl這樣的編程語言通常提供其他機制來調用標準庫函數stdbuf。 (在Perl中,可以在每次寫入後使用內置變量$|autoflush(BOOL) io handle方法強制刷新。)

當然,當程序成功終止時,所有輸出緩衝區都會「刷新」(srnt)各自的流)。所以

echo PING | grep -o 'PING' | grep -o 'IN' 

將立即輸出其唯一的輸出行。但是,除非您提供了計數命令行選項(-c N;請參閱man ping),否則ping不會終止。因此,如果您需要立即管道吞吐量,則可能需要修改緩衝行爲。

+1

感謝您的解釋!不幸的是,我的系統中沒有stdbuf,但爲什麼研究你提到的一些東西,我遇到了https://perl.plover.com/FAQs/Buffering.html 看起來像「$ | = 1」通過使標準輸出「熱」來禁用perl中的緩衝。所以這個: 'ping google.com | perl -pe'$ | = 1'| grep -o'IN'' 將立即打印「IN」。 – Robz