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つの議論があります。