私は同じファイルに2つの単語インスタンスがあるかどうかを調べる方法を探しています。これまでの検索を実行するには、以下を使用しました。
find . -exec grep -l "FIND ME" {} \;
私が経験している問題は、「FIND」と「ME」の間にスペースがないと検索結果からファイルが生成されないことです。 「FIND ME」の代わりに「FIND」と「ME」の両方が存在するファイルで、事前検索文字列をどのように調整できますか?
私はAIXを使用しています。
答え1
GNUツールの使用:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
標準的には次のことができます。
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
grep
ただし、これによりファイルごとに最大2つが実行されます。あまりにも多くgrep
を実行せずにファイル名に文字を許可しながら移植性を維持するには、次のようにします。
convert_to_xargs() {
sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\\"
print ""
}
line = $0
}'
END { print line }'
}
export LC_ALL=C
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
アイデアは、xargsの出力をfind
xargsに適した形式に変換することです(ここでは、空白(ロケールの場合はSPC / TAB / NL C
、他のロケールのYMMV)で区切られた単語のリストが必要です。ここで、一重引用符、二重引用符、バックスラッシュはスペースをエスケープできます。
通常の出力は後処理できませんfind -print
。なぜなら、ファイル名を改行で区切ってファイル名の改行をエスケープしないからです。たとえば、次のような場合があります。
./a
./b
b
呼び出されたディレクトリから1つのファイルを呼び出すのか、a<NL>.
現在のディレクトリから2つのファイルを呼び出すのかわかりません。a
b
を使用すると、ファイルパスに出力として表示できない.//.
ため(空の名前を持つディレクトリは存在せず、ファイル名には許可されていないため)が含まれている行が表示された場合は、次のことがわかります。 new ファイル名の最初の行です。したがって、このコマンドを使用して、この行の前の行を除くすべての改行をエスケープできます。//
find
/
//
awk
上記の例を取ると、find
出力は最初のケース(ファイル1つ)になります。
.//a
./b
awkは次にエスケープされます。
.//a\
./b
したがって、これはxargs
引数と見なされます。 2番目のケース(2つのファイル):
.//a
.//b
これはawk
そのままですので、xargs
両方のパラメータを参照してください。
任意のバイトシーケンスで作業するには(ユーザーロケールで有効な文字を形成しなくても)、単純化するために(そしていくつかの実装)LC_ALL=C
が必要です。sed
awk
xargs
スペースSPCとTABのみを定義し、バックスラッシュを含むエンコードされた文字を異なる方法で解釈するさまざまなユーティリティの問題を回避します。
答え2
ファイルが単一のディレクトリにあり、名前にスペース、タブ、改行、または文字が含まれていない、または*
で始まらない場合は、?
MEを含むファイルのリストを取得し、FINDも含めるように範囲を狭めます。[
-
.
grep -l FIND `grep -l ME *`
答え3
awk
以下も実行できます。
find . -type f -exec awk 'BEGIN{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; END{if (cx > 0 && cy > 0) print FILENAME}' {} \;
cx
と を使用して、cy
それぞれ一致する行数を計算します。そのブロックの両方のカウンタがゼロより大きい場合、印刷はより速く効率的です。FIND
ME
END
FILENAME
gnu awk
find . -type f -exec gawk 'BEGINFILE{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; ENDFILE{if (cx > 0 && cy > 0) print FILENAME}' {} +
答え4
許可された答えを見ると、必要以上に複雑に見えます。 GNUバージョンはNULLで終わる文字列をサポートしてfind
います。とても簡単です:grep
xargs
find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l ME
コマンドを変更してfind
ファイルをフィルタリングできます。これは、解析に複雑さを追加することなく、すべての文字を含むファイル名に対して機能しますsed
。ファイルをさらに処理するには、--null
最後に別のファイルを追加してください。grep
find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l --null ME | xargs -0 echo
そして関数として:
find_strings() {
find . -type f -print0 | xargs -0 grep -l --null "$1" | xargs -0 grep -l "$2"
}
明らかに、これらのツールを実行しているGNUバージョンがない場合は、許可された答えを使用してください。