grep 沒有為變數中傳遞的目錄提供輸出

grep 沒有為變數中傳遞的目錄提供輸出

我正在嘗試編寫一個bash腳本,用於搜尋指定目錄樹中的檔案內容是否存在指定的子字串。

單獨使用 的grep遞歸函數是不夠的,因為我可能需要迭代/系統的目錄(和所有子目錄),這會導致grep記憶體不足併中止。因此,我決定使用以下變數來獲取指定目錄樹中所有目錄和子目錄的列表,find這些變數表示傳遞給腳本的參數。

searchdir=$HOME     # passed in a script argument
searchstr="secret"  # passed in a script argument

我調用該find實用程式並將輸出儲存到臨時檔案。

TF=$(mktemp)
find ${searchdir} -type d 1>$TF 2>/dev/null

使用臨時檔案中所有目錄的列表,我繼續使用循環迭代該檔案的行,while-do以便對每個目錄中的所有檔案執行搜尋。對於grep,我使用中提供的參數格式這個答案搜尋單一目錄中的所有文件,包括隱藏文件。

cat $TF | while read line || [[ -n $line ]];
do
    grepdir="${line}/{*,.*}"
    grep -sHn "${searchstr}" ${grepdir}
done

....但是,該程式碼不會產生任何輸出。

我驗證了...

${TF}包含所有目錄的正確列表。輸出${grepdir}變數給出了我期望找到的輸出。

/home/user/{*,.*}
/home/user/.ssh/{*,.*}
/home/user/test/{*,.*}
# ... and so on

如果我grep使用硬編碼目錄運行命令,特別是該~/test/目錄,其中包含兩個測試檔案以及應該找到的字串

grep -sHn "${searchstr}" /home/user/test/{*,.*}

...它正確輸出包含子字串“secret”的兩個檔案。

/home/user/test/asdf:7:secret
/home/user/test/test.txt:5:asdfasfdsecretaasdfafd

對我有用的格式是最初在回答討論遞歸使用grep。如果我這樣做:

cat $TF | while read line || [[ -n $line ]];
do
    grep -rn "${line}" -e "${searchstr}"
done

....我得到一些輸出(技術上正確,但有許多重複的條目),但由於正在grep遞歸地處理目錄並且我有所有目錄的列表,因此我一定會在目錄上多次獲得相同的結果,例如上述根目錄grep將完全失敗,這是我試圖避免的。


我還應該提到的是,我為了讓它工作而拼命的黑客,例如$(echo "${grepdir}")作為參數傳遞,也導致沒有結果。

我的想法或理解很可能有誤解bash。在調用之前不應該bash擴展變數嗎?我的腳本哪裡出錯了?${grepdir}grep

答案1

規則#1:當命令或腳本沒有按照您的意願執行時, 查看錯誤訊息。  不要把它們丟進 /dev/null.

您收到類似錯誤訊息

grep: /home/user/{*,.*}: No such file or directory
grep: /home/user/.ssh/{*,.*}: No such file or directory
grep: /home/user/test/{*,.*}: No such file or directory

但你沒有看到他們。

如果我們看一下重擊(1), 我們看

擴展是在命令列上被分割成單字後執行的。執行了七種擴展:大括號擴展、波形符擴展、參數和變數擴展、命令替換、算術擴展、分詞和路徑名擴展。

展開的順序是:大括號展開;波形符擴展、參數和變數擴展、算術擴展和命令替換(以從左到右的方式完成);分詞;和路徑名擴展。

對於您的情況來說,重要的部分是大括號擴展發生在變數擴展之前。所以,如果你說

grep -sHn "${searchstr}" "${line}"/{*,.*}

然後

  • 大括號擴充會將最後一個標記變成"${line}"/*and "${line}"/.*
  • 變數擴充會將上面的內容變成/home/user/*and /home/user/.*,然後
  • 路徑名擴充會將上面的內容轉換為檔案名稱清單。

但是,當你說

grep -sHn "${searchstr}" ${grepdir}

然後

  • 變數擴展將最後一個標記變成/home/user/{*,.*},

然後大括號擴展發生就為時已晚。  grep尋找名為literal 的檔案/home/user/{*,.*}


聚苯乙烯

grep -sHn "${searchstr}" "${line}/{*,.*}"

也不起作用,因為引號會阻止大括號擴展和路徑名擴展的發生。

PPS:你不需要那麼多牙套;

grep -sHn "$searchstr" "$line"/{*,.*}

就可以了。

答案2

grep 在整個系統上遞歸時中止的原因可能不是它無法處理大量數據,而是它在 /proc、/sys 或 /dev 中的一個或另一個偽檔案或裝置檔案上出錯。您可以使用--exclude命令列上的選項排除有問題的目錄。

它不擴展通配符的原因是因為它們在這一行中被引用:

    grepdir="${line}/{*,.*}"

將其更改為這一點可能有助於它們的擴展。

    grepdir="${line}/"{*,.*}

實現此目的的另一種方法(代表您編寫較少的腳本)是使用檔案路徑來選擇檔案find並將檔案路徑傳遞到xargs進行處理:find / ... -print 0 | xargs -0 ...

然而,無論哪種方式都可能仍然會絆倒原始遞歸 grep 絆倒的任何文件,除非您排除它們。

相關內容