1. 概要

Linuxコマンドラインでは、 grep は、ファイル内のテキストを検索するために使用する便利なユーティリティです。 ただし、 grep は、最初に特定の基準に対してファイルをフィルタリングしてから、その内容を調べることはできません。

この要件は、ディレクトリの下のすべての*。txtファイルでテキストを再帰的に検索したり、名前にタイムスタンプが含まれているすべてのファイルでパターンを検索したりするなど、日常業務で頻繁に発生します。

このチュートリアルでは、フィルタリングされたファイルのセットに対してgrepを実行する方法を説明します。

2. サンプルファイル

チュートリアルのコマンドをより簡単に理解するために、テスト用のディレクトリ構造の例を作成しましょう。

$ tree test 
test
├── app
│   ├── change_log.log
│   └── readme.md
├── archive
│   ├── app_20200101.log.archive
│   └── app_20200201.log.archive
└── log
    ├── app_20200301.log
    ├── app_20200401.log
    └── app.log

3 directories, 7 files

テスト、の下に3つのサブディレクトリがあり、各ディレクトリにはいくつかのファイルがあります。

この例では、テストディレクトリの下にあるすべてのファイルに「Exception」という単語が含まれています。この事実は、grepコマンドで確認できます。

$ grep -R 'Exception' test
test/app/change_log.log:Fix the NullPointerException Problem when calling external APIs
test/app/readme.md: - Exceptions are well handled
test/archive/app_20200101.log.archive:DATETIME - [Error] NullPointerException has Occurred
test/archive/app_20200201.log.archive:DATETIME - [Error] NullPointerException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred
test/log/app.log:DATETIME - [Error] NullPointerException has Occurred

ここで、この test ディレクトリを例として取り上げ、フィルタリングされたファイルセットでgrepコマンドを実行する方法について説明します。

3. 特定の拡張子を持つファイルのみのgrep

3.1. grep コマンドの–include =GLOBオプションの使用

まず、*。log拡張子のファイルでのみパターン「Exception」を検索する方法を見てみましょう。

$ grep -R --include=*.log 'Exception' test
test/app/change_log.log:Fix the NullPointerException Problem when calling external APIs
test/log/app.log:DATETIME - [Error] NullPointerException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred

上記の出力が示すように、ファイル拡張子が「log」のファイルのみがgrepコマンドによってチェックされます。

grep コマンドにそれを行うように指示するために、2つのオプションを使用しました。

  • -Rはファイルを再帰的に検索します。 つまり、testの下の任意のサブディレクトリにあるファイルで指定されたパターンを検索します。
  • –include =*。logは、 –include = GLOBオプションの例であり、ベース名が指定されたGLOB式と一致するファイルのみを検索するようにgrepに指示します。

また、複数の –include = GLOB オプションを使用して、grepコマンドに複数の拡張子に一致するファイルを検索するように依頼できます。

それでは、*。logファイルと*。mdファイルで「Exception」という単語を検索してみましょう。

$ grep -R --include=*.log --include=*.md 'Exception' test
test/app/readme.md: - Exceptions are well handled
test/app/change_log.log:Fix the NullPointerException Problem when calling external APIs
test/log/app.log:DATETIME - [Error] NullPointerException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred

ご覧のとおり、ファイル test / app /readme.mdも出力に表示されます。

または、1つの –include オプションを使用して、GLOB式に複数の拡張子を含めることもできます。 次のコマンドは同じ出力を出力します。

$ grep -R --include=*.{log,md} 'Exception' test

3.2. BashGLOBを使用したファイルのフィルタリング

grep –include = GLOB オプションは、grepに特定の拡張子を持つファイルのみを検索するように指示できることを学びました。

または、 Bashのバージョンが4以上の場合、Bashのglobstar(**)を使用してファイルを再帰的に照合できます

$ grep 'Exception' test/**/*.log
test/app/change_log.log:Fix the NullPointerException Problem when calling external APIs
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app.log:DATETIME - [Error] NullPointerException has Occurred

今回は、grepコマンドは非常に単純に見えます。 Bash GLOBがファイルのフィルタリングを担当している間、指定されたファイルのパターン「Exception」の検索のみを担当します。

さらに、Bash GLOB式を拡張して、複数のファイル拡張子に一致させることもできます。 「*。log」ファイルと「*。md」ファイルで同じ検索を実行してみましょう。

$ grep 'Exception' test/**/*.{log,md}
test/app/change_log.log:Fix the NullPointerException Problem when calling external APIs
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app.log:DATETIME - [Error] NullPointerException has Occurred
test/app/readme.md: - Exceptions are well handled

上記の出力を確認すると、「test / app /readme.md」もリストに含まれていることがわかります。

4. findコマンドとgrepコマンドの組み合わせ

特定の拡張子を持つファイルのみを検索する方法を学びました。これは非常に一般的な使用例です。 ただし、異なる基準でフィルタリングされたファイルを検索したい場合があります。

たとえば、特定のユーザーが所有するファイル、特定のパターンに一致するファイル名、または最終アクセス時刻がタイムスタンプより前または後のファイルなどでのみテキストを検索したい場合があります。

さまざまな基準を使用してファイルをフィルタリングする場合は、親友であるfindコマンドを忘れないでください。

このチュートリアルでは、高度な基準を使用してファイルを検索する方法の詳細については説明しません。 代わりに、grepfindを連携させる方法に焦点を当てます。 つまり、 grep は、findの結果でファイルを検索します。

「」という単語を検索します例外 」など、ファイル名にタイムスタンプが付いているファイル app_20200301.log app_20200101.log.archive。 

まず、findコマンドを見てこれらのファイルを取得しましょう。

$ find test -type f -a -regextype 'egrep' -regex '.*_[0-9]{8}.*' 
test/archive/app_20200201.log.archive
test/archive/app_20200101.log.archive
test/log/app_20200401.log
test/log/app_20200301.log

上記の出力が示すように、find-regexオプションを使用して、検索するファイルをフィルタリングします。

それでは、findコマンドの結果に対してgrepを機能させる方法を見てみましょう。

4.1. find-execアクションの使用

grepfindの結果で機能させる1つの方法は、find-execアクションを使用することです。

$ find test -type f -a -regextype 'egrep' -regex '.*_[0-9]{8}.*' -exec grep -H "Exception" '{}' \;
test/archive/app_20200201.log.archive:DATETIME - [Error] NullPointerException has Occurred
test/archive/app_20200101.log.archive:DATETIME - [Error] NullPointerException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred

見つかった各ファイルは、-execアクションのプレースホルダー「{}」を埋めます。 このようにして、grepコマンドは見つかった各ファイルを検索します。

このコマンドには、末尾に「\;」が必要です。 これは、grepコマンドの終了を示しているためです。

-execアクションは、findコマンドが検出した各ファイルに対して実行されることに注意してください。つまり、 find が100万個のファイルを配信する場合、 -execアクションを100万回実行します。

明らかに、 -exec アクションのパフォーマンスは、膨大な数のファイルでテキストを検索する場合には良くありません。

次に、findgrepをより効率的に機能させる方法を見てみましょう。

4.2. xargsを使用してfindgrepを組み合わせる

find-execアクションとは異なり、 xargsは、見つかったファイルをバンドルにビルドし、コマンドを可能な限り実行します

これは、特に多数のファイルを検索する場合に、-execアクションよりも大きな利点です。

最後に、 xargs コマンドを使用して、findgrepを組み合わせてみましょう。

$ find test -type f -a -regextype 'egrep' -regex '.*_[0-9]{8}.*' | xargs grep "Exception" 
test/archive/app_20200201.log.archive:DATETIME - [Error] NullPointerException has Occurred
test/archive/app_20200101.log.archive:DATETIME - [Error] NullPointerException has Occurred
test/log/app_20200401.log:DATETIME - [Error] ClassCastException has Occurred
test/log/app_20200301.log:DATETIME - [Error] SQLException has Occurred

5. 結論

この記事では、特定の条件に一致するファイルに対してgrepを実行する方法を学習しました。

さらに、find-execアクションとxargsコマンドの違いについても説明しました。 より良いパフォーマンスを得たい場合は、xargsが適切なツールです。