パターン A のファイルを grep し、パターン B のファイルを除外する

パターン A のファイルを grep し、パターン B のファイルを除外する

パターン A (iwant) を含むファイルを grep したいのですが、パターン B (idontwant) を含むファイルは除外したいです。

例:

read -p "...what are you looking for: " iwant
read -p "...what should not be included: " idontwant

iwant="blue car" 
idontwant="red car"

以下のファイルがあると仮定します。

-rw-rw-r--.  1 terpentin terpentin  45 Jun  8 16:04 blue.car
-rw-rw-r--.  1 terpentin terpentin  44 Jun  8 16:05 mixed.car
-rw-rw-r--.  1 terpentin terpentin  40 Jun  8 16:04 red.car
find . -type f -print -exec cat {} \;

./mixed.car
blue car
red car
blue car

./red.car
red car
red car
red car

./blue.car
blue car
blue car
blue car

結果として「./blue.car」ファイルのみを取得するにはどうすればよいでしょうか?

元のコンテンツには何百もの長いテキスト ファイルが含まれているため、リソースをできるだけ効率的に使用することが重要です。

答え1

使用

find . -type f ! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' -print

または

find . -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' -print
  • コマンド内の用語(「述語」と呼ばれることもある)は、find 次のように特徴付けられます。テスト(例 -type f)および行動(例えば 、 -printおよび -delete)。マニュアルページから、-execアクションそして テスト. だから、
    検索 . -type f -mtime -30 -name '*.txt' -readable -size +5テスト6 テスト7 テスト8
    すべての条件を満たすファイル(指定されたすべてのテストを満たすファイル)に検索範囲を絞り込みます。
    検索.-execコマンド1{} ';' -execコマンド2{} ';' -execコマンド3{} ';' …
    すべてのコマンドが成功するファイルを検索します。
  • どのfindテストも、 を前に付けることによって否定 (反転) できます!。つまり、find . ! -type dプレーン ファイル、シンボリック リンク、名前付きパイプ、ソケット、デバイス ファイルなど、ディレクトリ以外のすべてを検索します。
  • ! -exec grep …は と同じではないことに注意してください-exec grep -v …。  -exec grep -v …は、少なくとも1行が一致しないファイルを検索します。 は、次  ! -exec grep …のファイルを検索します。いいえ行が一致します。
  • -qのオプションは正式grepには の同義語です--quietが、次の意味もあります。素早い出力は何も書きません(エラーメッセージは例外ですが、該当する場合は例外です)。また、一致するものを見つけるとすぐに終了します。すべてのファイルを最後まで読み込んで一致するものを見つけるわけではありません。一致します。(もちろん、ファイルに一致するものが含まれていない場合は、grepそれを判断するためにファイル全体を読み取る必要があります。)
  • それで (要約)コマンドは、
    grep -q "$iwant"     ファイル
    成功し、
    grep -q "$idontwant"ファイル
    は失敗します( が前に付いているため!)。
  • 2つのコマンドは機能的に同等ですが、パフォーマンスが異なる場合があります(つまり、実行にかかる時間が異なる可能性があります)。検索文字列を含むファイルが少数の場合、
    検索 . -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' –print
    はほとんどのファイルを削除するので、より高速になりますgrep "$iwant"。多くのファイルに両方の文字列が含まれている場合は、
    検索 . -type f ! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' –print
    ! grep "$idontwant"ほとんどのファイルが削除される ため、より高速になります。

答え2

次のように、GNU grepregex と grep オプションを適切に選択してファイル名の抽出を実行できます。

$ grep -lzPsr '(?s:(?=.*blue)(?!.*red))' .

ファイル全体が 1 つの大きな行として扱われる slurp モード (-z) で grep を操作しています。

-l は正規表現に一致するファイルの名前を一覧表示します。

-r は、現在のディレクトリとそれ以下のすべてのファイルに対して再帰的に実行されます。

-s は grep を無音化し、警告を発しないようにします。

正規表現は、ファイル内の青の存在と赤の不在を検索し、それが「はい」であると判定します。

-P は grep で Perl 正規表現エンジンを呼び出すので、pcre 正規表現の利点を活用できます。

関連情報