grepが特殊ファイル名を処理できるようにする

grepが特殊ファイル名を処理できるようにする

名前にtxtスペースや特殊文字(例:#

があるが存在しないすべての項目を一覧表示するgrepソリューションがあります。grep -L "cannot have" $(grep -l "must have" *.txt)must havecannot 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"

アイデアは、-ZNULで区切られたファイル名のリストを印刷し、xargs -r0そのリストを2番目のgrep

デフォルトでは、コマンド置換はスペース、タブ、および改行(およびではNUL)にzsh分割されます。 Bourneなどのシェルは、zsh分割によって引き起こされる各単語に対してワイルドカード操作も実行します。

次のことができます。

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

代わりにシェルコマンドを試してくださいfindgrep

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

関連情報