2017-07-27 81 views
0

我有一個bash腳本,包括像這樣的一行:bash命令替換凍結腳本(輸出太長?) - 如何應對

matches="`grep --no-filename $searchText $files`" 

換句話說,我分配的grep的結果到一個變量。

我最近發現那行代碼似乎有一個漏洞:如果grep發現太多結果,它會令人討厭地簡單地凍結執行。

首先,如果任何人都可以確認輸出過多(確切地說是什麼構成過多)是已知的命令替換危險,請爲我提供一個可靠的鏈接。我搜索了網頁,並且可以找到的最接近的參考文獻是this link

「不要爲長文本文件的內容設置變量,除非您有足夠的理由這麼做。」

暗示存在危險,但非常不足。

其次,是否有一個已知的最佳做法來應對這個問題?

我真正想要的行爲是在命令替換 中生成一個很好的人類可讀的錯誤消息,然後是錯誤退出代碼,以便我的腳本將終止而不是凍結。 (注意:我總是使用「set -e」作爲其中一行來運行我的腳本)。有什麼辦法可以得到這種行爲嗎?

目前,我知道的唯一解決方案就是一種類似於我的直接案例的黑客行爲:我可以使用它的--max-count選項限制grep的輸出。

+0

「凍結執行」?不是真的。如果你沒有將ulimits設置爲適當地限制每個進程的內存分配,它可能會用完並且內存和失敗(不凍結),或者它可能會進入交換(這可能會使系統減速很多*) ,但沒有一個國家剛剛凍結。 –

+0

順便說一句,使用'set -e' [不一定是個好主意](http://mywiki.wooledge.org/BashFAQ/105)。 (如果閱讀過多,請忽略寓言,但* *要確定您是否理解'set -e'的行爲足以安全地使用它,就可以瞭解下面有多少測驗問題可以正確判斷。 –

+0

另一方面,'$ files'作爲一個沒有引號的擴展是一種代碼異味 - 例如,當存在帶空格的文件名時,你的代碼幾乎肯定無法正常工作,並且當名稱包含時也會令人驚訝全局元字符。最佳做法是將列表存儲在數組中;例如:'files =(* .txt)',然後解除引用'「$ {files [@]}」' –

回答

1

理想情況下,您不應該將未知長度的數據捕獲到內存中中,全部爲;如果您在需要時閱讀它,則grep將等待內容準備就緒。

即:

while IFS= read -r match; do 
    echo "Found a match: $match" 
    # example: maybe we want to look at whether a match exists on the filesystem 
    [[ -e $match ]] && { echo "Got what we needed!" >&2; break; } 
done < <(grep --no-filename "$searchText" "${files[@]}") 

這樣,grep只有當read準備消費它(和將阻塞的,而不是需要繼續讀取輸入,如果有已經比可以產生更多的輸出寫入一行存儲在相對較小的管道緩衝區中) - 因此,您不需要的名稱甚至不會首先生成,也無需分配內存或以任何其他方式處理它們。

+0

這是一個很好的解決方案,謝謝! – HaroldFinch

+0

Heh。如果我知道你在使用cygwin,我可能沒有建議進程替換('<()'語法) - 它有一個長期存在的bug影響它 - 但它變成了上游[最終得到了修正](https ://cygwin.com/ml/cygwin/2013-04/msg00120.html)。 –