
我想要 grep 包含模式 A (iwant) 的文件,但我想排除包含模式 B (idontwant) 的文件。
例子:
read -p "...what are you looking for: " iwant
read -p "...what should not be included: " idontwant
iwant="blue car"
idontwant="red car"
假設我有以下文件:
-rw-rw-r--. 1 terpentin terpentin 45 Jun 8 16:04 blue.car
-rw-rw-r--. 1 terpentin terpentin 44 Jun 8 16:05 mixed.car
-rw-rw-r--. 1 terpentin terpentin 40 Jun 8 16:04 red.car
find . -type f -print -exec cat {} \;
./mixed.car
blue car
red car
blue car
./red.car
red car
red car
red car
./blue.car
blue car
blue car
blue car
怎麼可能只得到文件“./blue.car”作為結果?
原始內容包括數百個長文本文件,因此盡可能節約資源非常重要。
答案1
使用
find . -type f ! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' -print
或者
find . -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' -print
- 命令中的術語(有時稱為“謂詞”)
find
的特徵為測試(例如,-type f
)和行動(例如,-print
和-delete
)。從手冊頁可能很難弄清楚-exec
兩者都是 行動和一個 測試。所以,正如尋找 。 -type f -mtime -30 -name '*.txt' -可讀 -size +5測試6 測試7 測試8……
連續將搜尋範圍縮小到滿足所有條件的檔案(滿足所有指定的測試),因此尋找 。 -執行命令1{} ';' -執行命令2{} ';' -執行命令3{} ';' ……
尋找所有指令都成功的檔案。 - 任何
find
測試都可以透過在其前面加上 來否定(反轉)!
。因此find . ! -type d
可以找到普通檔案、符號連結、命名管道、套接字和裝置檔案——除了目錄之外的所有檔案。 - 請注意,
! -exec grep …
不等於-exec grep -v …
。-exec grep -v …
將找到至少有一行不符的文件。! -exec grep …
會在哪裡找到文件不線條匹配。 - 選項
-q
togrep
是 的正式同義詞--quiet
,但它也意味著快的。它不會寫入任何輸出(可能除了錯誤訊息(如果適用)),一旦找到匹配項它就會退出 - 它不會讀取每個文件到末尾來查找每一個匹配。 (當然,如果文件不包含任何匹配項,則grep
必須完整讀取它才能確定。) - 所以 (長話短說)命令查找其文件
grep -q“$iwant” 文件
成功並且grep -q“$idontwant”文件
失敗(因為我們在它前面加上了!
)。 - 這兩個命令在功能上是等效的,但可能具有不同的效能(即,可能需要不同的運行時間)。如果只有幾個檔案包含搜尋字串,
尋找 。 -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' -列印
會更快,因為這grep "$iwant"
會消除大部分文件。如果許多文件都包含這兩個字串,則尋找 。 -輸入f! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' -列印
會更快,因為這! grep "$idontwant"
會消除大部分文件。
答案2
我們可以透過GNU grep
明智地選擇 regex 和 grep 選項來執行檔案名稱提取:
$ grep -lzPsr '(?s:(?=.*blue)(?!.*red))' .
我們在 slurp 模式 (-z) 下運行 grep,其中整個檔案被視為一大行。
-l 將列出與正規表示式相符的檔案的檔案名稱。
-r 將在目前目錄下的所有檔案上遞歸運行。
-s 將使 grep 靜默,不發出任何警告。
正規表示式將查找文件中是否存在藍色且不存在紅色,以便回答「是」。
-P 在 grep 中呼叫 Perl 正規表示式引擎,以便我們可以利用 pcre 正規表示式的優勢。