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:當命令或腳本沒有按照您 的意願執行時,請查看錯誤消息。 不要把它們扔進
/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
但你沒有看到它們。
如果我們查看bash(1),我們會看到
將其拆分為單詞後在命令行上執行擴展。執行的擴展有七種:大括號擴展、波浪號擴展、參數和變數擴展、命令替換、算術擴展、分詞和路徑名擴展。
展開順序為:大括號展開;波浪號擴展、參數和變數擴展、算術擴展和命令替換(以從左到右的方式完成);分詞;和路徑名擴展。
您的情況的重要部分是大括號擴展發生在變數擴展之前。所以,如果你說
grep -sHn "${searchstr}" "${line}"/{*,.*}
然後
- 大括號擴展會將最後一個標記變成
"${line}"/*
and"${line}"/.*
,- 變數擴展會將上面變成
/home/user/*
and/home/user/.*
,然後- 路徑名擴展會將上述內容轉換為文件名列表。
但是,當你說
grep -sHn "${searchstr}" ${grepdir}
然後
- 變數擴展將最後一個標記變成
/home/user/{*,.*}
,然後大括號擴展發生為時已晚。
grep
查找名為字面意思的文件/home/user/{*,.*}
。附言
grep -sHn "${searchstr}" "${line}/{*,.*}"
也不起作用,因為引號會阻止大括號擴展和路徑名擴展的發生。
PPS 你不需要所有的牙套;
grep -sHn "$searchstr" "$line"/{*,.*}
會好的。