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 で 1 回のパスで実行できます。
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 の回答と同様に、awk コマンドを -f を使用してファイルに入れることができます。また、ほとんどの場合と同様に、必要に応じて簡単に perl に変換できます。)
答え2
すでに GNU 固有のオプション ( -L
) を使用しているので、次のようにすることができます。
grep -lZ -- "must have" *.txt | xargs -r0 grep -L -- "cannot have"
アイデアは、 を使用して-Z
NUL 区切りのファイル名のリストを印刷し、 を使用して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
代わりにを使用しfind
、grep
シェル コマンドを使用することを検討してください。
find . -name '*.txt' -print0 | xargs -0 -I{} sh -c 'grep -q "must have" -- "{}" && grep -L "cannot have" -- "{}"'