為什麼這個單行不能產生輸出?
以下在 bash 中不產生任何結果:
while true ; do upower -d ; sleep 1 ; done | grep percentage | uniq
我發現這條鏈中最後一個甚至倒數第二個程序是什麼並不重要。倒數第二個程序總是產生預期的輸出,而最後一個程序總是不能產生任何東西。
( while ... done )
如果我將 while 循環包裝在子外殼中(通過),或者將除最後一個命令之外的所有內容包裝在子外殼中並通過管道輸入最後一個命令,這似乎也無關緊要。我對這種行為深感困惑。
我的直覺告訴我…
…在鏈中存在某種 I/O 死鎖,這是由阻塞讀取和寫入以及 while 循環並不總是產生輸出這一事實造成的。但是,另一方面,我以前做過很多次這種事情,沒有問題。此外,如果是這樣,while循環和next命令之間不會存在問題嗎?所以我很困惑。如果沒有其他人可以重現,將提供 bash 版本資訊。
萬一不是很明顯…
這行程式碼的重點是列印電池百分比的每次變化,但只列印新的電池電量。它使用輪詢。我想我可以通過簡單地執行來獲得相同的行為
upower --monitor-detail | grep percentage | uniq
但這是一次性的事情,我不打算在上面花費超過 5 秒的時間,直到上面的方法開始失敗。在這一點上,它變成了一個有趣的問題。另外,無論如何,我不知道 monitor-detail 是否只是在後台進行輪詢(而且我沒有執行 strace 來檢查)。
編輯:顯然,上面的
--monitor-detail
版本也沒有產生任何東西(或者,至少,它似乎。輪詢/更新頻率非常低,所以我可能沒有等待足夠長的時間。雖然我知道我等待的時間足夠長原來的問題)。現在我非常非常困惑。我想我畢竟應該執行那個 strace ……
您應該使用
grep --line-buffered percentage
,否則grep
標準輸出緩衝區將需要很長時間才能被其輸出填充。
除了 Marco d’Itri 的回答之外,並非每個工具都支持自定義緩衝。如果您正在執行的工具沒有,或者您想使用自定義緩衝區大小執行它,您可以使用
stdbuf
覆蓋工具的緩衝行為;在這種情況下,例如,強制輸出為行緩衝:while true ; do upower -d ; sleep 1 ; done | stdbuf -oL grep 'percentage' | uniq
強制輸出無緩衝:
while true ; do upower -d ; sleep 1 ; done | stdbuf -o0 grep 'percentage' | uniq
要強制輸出以 512 B 的塊緩衝:
while true ; do upower -d ; sleep 1 ; done | stdbuf -o512 grep 'percentage' | uniq
您可以添加 K、M、G、
$$ … $$以 KB、MB、GB 為單位指定輸出,$$ … $$:
while true ; do upower -d ; sleep 1 ; done | stdbuf -o512K grep 'percentage' | uniq