GNUツールの場合:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
標準的に行うことができます:
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
ただし、ファイルごとに2つのgrepsが実行されます。その数grep
のsの実行を回避し、ファイル名に任意の文字を許可しながら移植性を維持するには、次のようにします。
convert_to_xargs() {
sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\\"
print ""
}
line = $0
}'
END { print line }'
}
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
の出力find
をxargsに適した形式(空白(SPC / TAB / NL、およびいくつかの実装でロケールから他の空白を期待)に変換することですxargs
)で区切られた単語のリスト。ブランクとお互いをエスケープします)。
一般にfind -print
、ファイル名を改行文字で区切り、ファイル名で見つかった改行文字をエスケープしないため、出力を後処理できません。たとえば、次の場合:
./a
./b
呼び出さb
れたディレクトリで呼び出されたのが1つのファイルなのかa<NL>.
、2つのファイルa
となのかを知る方法がありませんb
。
を使用すると.//.
、//
出力としてファイルパスに表示されないfind
ため(空の名前のディレクトリ/
は存在せず、ファイル名に使用できないため)、を含む行が表示される場合//
、それは新しいファイル名の最初の行。そのため、このawk
コマンドを使用して、改行文字以外のすべての改行文字をエスケープできます。
上記の例を使用するfind
と、最初のケースで出力されます(1つのファイル):
.//a
./b
どのawkは次のようにエスケープします:
.//a\
./b
したがって、xargs
それは1つの引数と見なされます。2番目の場合(2つのファイル):
.//a
.//b
これawk
はそのままになりxargs
ますので、2つの議論があります。