2つの異なる単語(順序、行)があるかどうかをテキストファイルを検索します。

2つの異なる単語(順序、行)があるかどうかをテキストファイルを検索します。

私は同じファイルに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の出力をfindxargsに適した形式に変換することです(ここでは、空白(ロケールの場合はSPC / TAB / NL C、他のロケールのYMMV)で区切られた単語のリストが必要です。ここで、一重引用符、二重引用符、バックスラッシュはスペースをエスケープできます。

通常の出力は後処理できませんfind -print。なぜなら、ファイル名を改行で区切ってファイル名の改行をエスケープしないからです。たとえば、次のような場合があります。

./a
./b

b呼び出されたディレクトリから1つのファイルを呼び出すのか、a<NL>.現在のディレクトリから2つのファイルを呼び出すのかわかりません。ab

を使用すると、ファイルパスに出力として表示できない.//.ため(空の名前を持つディレクトリは存在せず、ファイル名には許可されていないため)が含まれている行が表示された場合は、次のことがわかります。 new ファイル名の最初の行です。したがって、このコマンドを使用して、この行の前の行を除くすべての改行をエスケープできます。//find///awk

上記の例を取ると、find出力は最初のケース(ファイル1つ)になります。

.//a
./b

awkは次にエスケープされます。

.//a\
./b

したがって、これはxargs引数と見なされます。 2番目のケース(2つのファイル):

.//a
.//b

これはawkそのままですので、xargs両方のパラメータを参照してください。

任意のバイトシーケンスで作業するには(ユーザーロケールで有効な文字を形成しなくても)、単純化するために(そしていくつかの実装)LC_ALL=Cが必要です。sedawkxargsスペースSPCとTABのみを定義し、バックスラッシュを含むエンコードされた文字を異なる方法で解釈するさまざまなユーティリティの問題を回避します。

おすすめ記事