
パターン 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 grep
regex と grep オプションを適切に選択してファイル名の抽出を実行できます。
$ grep -lzPsr '(?s:(?=.*blue)(?!.*red))' .
ファイル全体が 1 つの大きな行として扱われる slurp モード (-z) で grep を操作しています。
-l は正規表現に一致するファイルの名前を一覧表示します。
-r は、現在のディレクトリとそれ以下のすべてのファイルに対して再帰的に実行されます。
-s は grep を無音化し、警告を発しないようにします。
正規表現は、ファイル内の青の存在と赤の不在を検索し、それが「はい」であると判定します。
-P は grep で Perl 正規表現エンジンを呼び出すので、pcre 正規表現の利点を活用できます。