Bash

grep 不為在變數中傳遞的目錄提供任何輸出

  • November 26, 2019

我正在嘗試編寫一個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"/{*,.*}

會好的。

引用自:https://unix.stackexchange.com/questions/554104