如果確定是 source code(如 C/C++)的一部分,這只是一碟小蛋糕:
grep -Prn --color --include=\*.{c,cpp,h} "pattern"尷尬的是有時根本不確定是存放在哪種檔案中(甚至可能不是文字檔),這時候就只好開地圖砲了:
find . -name "*" -exec sh -c "strings -f {} | grep 'pattern'" \;strings 指令會過濾出檔案中的 ASCII 可見字元,此時再用 pipe 餵給 grep 就安全了。
(雖然 grep 有個 --text 選項,但實際測試結果很不理想)
strings 的參數 -f 是顯示檔名,因此假如您想要再串 grep -v 過濾多餘的資料,比方說註解,以下方式是錯的:
find . -name "*" -exec sh -c "strings -f {} | grep 'pattern' | grep -P '^\s*(//|/\*)'" \;請改成:
find . -name "*" -exec sh -c "strings -f {} | grep 'pattern' | grep -P 'filename:^\s*(//|/\*)'" \;因為 strings 在輸出過濾後的檔案時也把檔名一併輸出給第一個 grep 了。
這個小技巧有兩個不完美的地方:
- 如果原本就是文字檔,丟給 strings 多此一舉,浪費效能
- 行號丟失:不過如果字串放在非文字檔裡,就沒有行號這種問題。
#!/bin/bash #fireinholde.sh IFS=$'\n' for filename in $(find . -name "*") do #is ASCII text? isAscii=$(file $filename | grep -P 'ASCII text$') if [ -n "$isAscii" ]; then grep -PHn $1 $filename else #no, you need strings it! result=$(strings $filename | grep -P $1) if [ -n "$result" ]; then for matched in $result do echo "$filename:$matched" done fi fi done不過在 SSD 越來越普及的現在,這一點效能損失應該是可以被忍受的,希望這個小技巧對大家有幫助 :)
讚哦!
回覆刪除