2つの異なる単語が存在するファイルを検索する方法は?


14

同じファイルに2つの単語インスタンスが存在するファイルを検索する方法を探しています。私はこれまで、次の方法で検索を実行してきました。

find . -exec grep -l "FIND ME" {} \;

私が遭遇している問題は、「FIND」と「ME」の間にちょうど1つのスペースがない場合、検索結果がファイルを生成しないことです。「FIND ME」ではなく「FIND」と「ME」の両方の単語がファイルに存在する以前の検索文字列をどのように適合させるのですか?

AIXを使用しています。


1
単語はファイル内のどこかに存在しますか、それとも常に同じ行にありますか?
-Sobrique

意図は同じ線でした。
チャドハリソン

言葉は同じライン上にある場合の代替は、正規表現を使用することですgrep -E/ egrepあなたが興味を持っているすべてのパターンを説明(および使用して、その+代わりに;、あなたの検索がサポートされている場合+
マット・ビアンコ

回答:


21

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


代わりにfind ... -print0and grep --nullを使用しないのはなぜですか?
ラズ

@razzed、どういう意味かわからない。grep --null(別名-Z)は最初のもので使用されますが、GNU拡張です。-print0(別のGNU拡張機能)はここでは役に立ちません。
ステファンシャゼラス

ありがとう。コマンドラインから引数として検索ディレクトリを取得するスクリプトにシェルコードをラップしたいと思います。私は.//.まだ何を意味するのかよくわかりませんが、コマンドラインから引数を受け入れるようにそれをどのように変更できるの$1でしょうか?
ティム

ありがとう。コマンドでは、-print0with findおよび-0with を使用する必要がありますxargsか?
ティム

@ティム、あなたが何を意味するのか分かりません。私はfind -print0答えのどこにも使いません。
ステファンシャゼラス

8

ファイルが単一のディレクトリにあり、その名前にスペース、タブ、改行、文字も含まれておらず*?norで[始まら-ない.場合は、MEを含むファイルのリストを取得し、それをFINDも含まれています。

grep -l FIND `grep -l ME *`

これにはさらに投票が必要です!! 「受け入れられた」答えよりもはるかにエレガントです。私のために働いた。
-roblogic

grep -l CategoryLinearAxis `grep -l labelJsFunction *`両方の属性が含まれているファイルを探している間に、ちょうどそうでした。なんて完璧な方法でしょう。+1
WEBjuju

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ブロック、両方のカウンタ> 0ならば、それが印刷さ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}' {} +

2

または、これを使用するegrep -eか、次のgrep -Eようにします。

find . -type f -exec egrep -le '(ME.*FIND|FIND.*ME)' {} \;

または

find . -type f -exec grep -lE '(ME.*FIND|FIND.*ME)' {} +

+(サポートされている場合)を行うには、コマンドであることに引数として複数のファイル(パス)名を追加見つける-exec編。これによりプロセスが節約され、\;見つかったファイルごとにコマンドを1回呼び出すよりもはるかに高速になります。

-type f ディレクトリでのgrepを回避するために、ファイルのみに一致します。

'(ME.*FIND|FIND.*ME)'「ME」の後に「FIND」または「FIND」の後に「ME」が続くすべての行に一致する正規表現です。(シェルが特殊文字を解釈しないようにするための単一引用符)。

コマンドにa -iを追加して、grep大文字と小文字を区別しないようにします。

「ME」の前に「FIND」がある行のみを一致させるには、を使用します'FIND.*ME'

単語の間にスペース(1つ以上、ただしそれ以外)を必要とするには: 'FIND +ME'

単語間にスペース(0以上、ただしそれ以外)を許可するには: 'FIND *ME'

組み合わせは正規表現では無限であり、一度に1行ずつのマッチングにのみ関心がある場合、egrepは非常に強力です。


ほとんどのgrepsは「-r」をサポートしていませんか?これにより「検索」が排除されますが、検索対象のツリーにソケットまたはその他の非プレーンファイルが存在する場合があります。
盗難

OPはAIXを使用してfindおり、質問に含まれていました。
MattBianco

0

受け入れられた答えを見ると、必要以上に複雑に思えます。NULLで終わる文字列のGNUバージョンfindおよびgrepxargsサポートします。次のように簡単です:

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バージョンを実行していない場合、明らかに、受け入れられた答えを使用してください。


1
--null--print0-0全てGNUの拡張です。それらのいくつかは現在他の実装で見られますが、それらはまだ移植性がなく、POSIXまたはUnix標準ではありません。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.