讓 grep 處理特殊檔名

讓 grep 處理特殊檔名

我有一組txt文件,其名稱可能包含空格或特殊字符,例如#.

我有一個grep解決方案grep -L "cannot have" $(grep -l "must have" *.txt)來列出所有具有must have但不具有cannot have.

例如,有一個文件abc defg.txt僅包含 1 行:must have.

所以通常 grep 解決方案應該找出abc defg.txt,但它會返回:

grep: abc: No such file or directory
grep: defg.txt: No such file or directory

我認為對於包含 的檔名#,grep 解決方案也是無效的。

誰能幫我修改 grep 解決方案嗎?

答案1

如果如果你願意走得更遠,awk 可以一次完成:

awk 'function s(){if(a&&!b){print f}} FNR==1{s();f=FILENAME;a=b=0} 
  /must have/{a=1} /cannot have/{b=1} END{s()}' filepattern

對於最近的 gawk,您可以使用 BEGINFILE 和 ENDFILE 來簡化。 (像所有 awk 答案一樣,您可以使用 -f 將 awk 命令放入檔案中,並且像大多數一樣,如果您願意,您可以輕鬆轉換為 perl。)

答案2

由於您已經在使用 GNU 特定選項 ( -L),您可以這樣做:

grep -lZ -- "must have" *.txt | xargs -r0 grep -L -- "cannot have"

這個想法是用於-Z列印 NUL 分隔的文件名列表,並用於xargs -r0將該列表作為參數傳遞給第二個grep.

預設情況下,命令替換按空格、製表符和換行符(以及 中的 NUL zsh)進行分割。類似於 Bourne 的 shellzsh也對分裂產生的每個單字執行通配符操作。

你可以這樣做:

IFS='
' # split on newline only
set -f # disable globbing
grep -L -- "cannot have" $(
    set +f # we need globbing for *.txt in this subshell though
    grep -l -- "must have" *.txt
  )

但這仍然會破壞包含換行符的檔案名稱。

zsh(且zsh僅),您可以執行以下操作:

IFS=$'\0'
grep -L -- "cannot have" $(grep -lZ -- "must have" *.txt)

或者:

grep -L -- "cannot have" ${(ps:\0:)"$(grep -lZ -- "must have" *.txt)"}

答案3

考慮使用shell 指令來find代替:grep

find . -name '*.txt' -print0 | xargs -0 -I{} sh -c 'grep -q "must have" -- "{}" && grep -L "cannot have" -- "{}"'

相關內容