Linux / コマンド / grep - 文字列と正規表現を検索する

grepは、ファイルやコマンドの出力から指定したパターンと一致する行を探すコマンドです。基本的な検索だけでなく、大文字小文字を無視した検索、一致しない行の選択、ディレクトリの再帰検索、正規表現、前後の文脈の出力までサポートします。

最も基本的な形はgrep 'パターン' ファイル名です。パターンにはシェルで特別な意味を持つ文字が含まれることがあるため、習慣的にシングルクォートで囲む方が安全です。

grepコマンドとは?

grepは入力を行単位で読み、パターンと一致する行を出力します。名前はUNIXのテキストエディタedのコマンド表現であるg/re/p、すなわち正規表現を全範囲で探して出力することから由来しています。

検索するファイルを指定しない場合は標準入力を読み込むため、他のコマンドの結果をパイプで渡して検索することができます。GNU grepの基本パターン文法は基本正規表現(Basic Regular Expression, BRE)であり、-Eを使用すれば拡張正規表現(Extended Regular Expression, ERE)を使用できます。

基本文法と最初の検索

例中のapp.logなどは、実際に読み取れるファイルに置き換えます。実装ごとに対応オプションが異なる場合があるため、grep --helpで確認してください。基本的な文法は次の通りです。角かっこは省略できる引数を示すため、実際のコマンドには入力しません。

grep [オプション] 'パターン' [ファイル...]

app.logの中にERRORが含まれる行を見つけるには、次のように実行します。

grep 'ERROR' app.log

複数のファイルを指定すると、各結果の前にファイル名が表示されます。

grep 'ERROR' app.log worker.log

標準入力も検索できます。次のコマンドはカーネルメッセージの中でusbを含む行を大文字と小文字を区別せずに表示します。

dmesg | grep -i 'usb'

dmesgが権限エラーになる場合は、まずシステムのログ閲覧ポリシーを確認し、許可された方法で読み取ります。入力側の失敗をgrepの「一致なし」と混同しないでください。

よく使うgrepオプション

オプション 機能 活用例
-i 大文字小文字を区別せずに検索 grep -i 'error' app.log
-v 一致しない行を選択 grep -v '^#' config
-n 結果に行番号を表示 grep -n 'TODO' main.c
-w パターンを完全な単語として検索 grep -w 'cat' words.txt
-x 行全体がパターンに一致する場合に選択 grep -x 'enabled' status.txt
-F パターンを正規表現ではなく固定文字列として処理 grep -F 'a.b' data.txt
-E 拡張正規表現を使用 grep -E 'error|failed' app.log
-r サブディレクトリを再帰的に検索 grep -r 'listen' /etc/nginx
-l 一致するファイル名のみを出力 grep -rl 'deprecated' src
-c ファイルごとの一致行数を出力 grep -c 'ERROR' app.log
-A, -B, -C 一致行の後・前・両方のコンテキストを出力 grep -C 2 'panic' app.log

これらのオプションは組み合わせて使用できます。例えば、grep -in 'error' app.log は大文字と小文字を区別せずに検索しながら行番号も表示します。詳細な動作や GNU 拡張オプションについては、GNU Grep 公式マニュアルで確認できます。

文字列と正規表現を区別する

固定文字列を -F で検索する

ドット、アスタリスク、角括弧のように正規表現で特別な意味を持つ文字を文字通り探すには -F が便利です。次のコマンドのドットは任意の1文字ではなく、実際のドットとして処理されます。

grep -F '192.168.0.1' access.log

検索語が単純な文字列であれば、不要なエスケープを減らして意図を明確にできます。

拡張正規表現は -E で使用する

-E を使うと、|、+、?、括弧などの拡張正規表現の文法をより読みやすく使用できます。次の例では ERROR、WARN、FATAL のいずれかを含む行を探します。

grep -E 'ERROR|WARN|FATAL' app.log

GNU grepでは、基本正規表現と拡張正規表現は主に表記方法の違いがあります。異なる環境との互換性が重要な場合は、対象システムのgrepの実装とサポートオプションを確認してください。

行の開始と終了を指定する

キャレット(^)は行の開始、ドル記号($)は行の終了を意味します。空行は開始と終了の間に文字がない^$で見つけることができます。

grep '^server' config.txt
grep 'completed$' job.log
grep '^$' notes.txt

設定ファイルで空行とコメント行を除外するには、次のように二つの条件を順番に適用できます。

grep -v '^[[:space:]]*#' app.conf | grep -v '^[[:space:]]*$'

検索範囲を正確に絞り込む

単語全体と行全体の一致

-wはパターンが単語全体に一致する行を選択します。例えばgrep -w 'cat'はcatを見つけますが、通常category内のcatは選択しません。

grep -w 'root' /etc/passwd

-xは行全体がパターンと正確に一致する場合のみ選択します。

grep -x 'active' service-status.txt

一致しない行を探す

-vは選択を逆に反転します。次の例はDEBUGが含まれていない行だけを出力します。

grep -v 'DEBUG' app.log

-iと組み合わせれば、大文字小文字を問わず除外できます。

grep -iv 'debug' app.log

複数のパターンを一度に検索する

-eを複数回使えば、それぞれのパターンを個別に指定できます。複雑な正規表現を1つにまとめる必要がなく、スクリプトで読みやすくなります。

grep -e 'ERROR' -e 'FATAL' app.log

パターンが多い場合は、1行に1つずつ書いたファイルを作り、-fで読み込むことができます。

grep -f patterns.txt app.log

ディレクトリ全体を再帰的に検索する

-rと-Rの違い

-rは、指定したディレクトリ以下のファイルを再帰的に検索します。コマンドラインで直接指定したシンボリックリンクは辿りますが、再帰検索中に出会ったシンボリックリンクはスキップします。

grep -rn 'database_url' ./config

GNU grepの-Rは、再帰検索中に出会ったシンボリックリンクまで辿ります。循環リンクや予想より広い検索範囲を作る可能性があるため、意図が明確な場合に使用します。

検索するファイル名を指定・除外する

--includeは指定したファイル名パターンだけを検索し、--excludeは一致するファイルをスキップします。シェルがアスタリスクを先に展開しないように、パターンは引用符で囲みます。

grep -rn --include='*.conf' 'timeout' /etc
grep -rn --exclude='*.min.js' 'deprecated' ./src

特定のディレクトリを除外するには--exclude-dirを使用します。

grep -rn --exclude-dir='.git' --exclude-dir='node_modules' 'api_key' .

一致するファイル名だけ確認する

一致した内容よりファイル一覧が必要な場合は-lを使用します。各ファイルは最初の一致が見つかるとそれ以上検索しないため、目的にも適しています。

grep -rl --include='*.html' 'jb-heading' .

逆に、パターンに一致しないファイルだけを探す場合は、大文字の-Lを使用します。

grep -rL --include='*.html' 'jb-heading' .

結果を読みやすく出力する

行番号とファイル名を表示する

-nは一致した行の番号を表示します。ファイルが1つだけの場合でも、ファイル名を強制的に表示したい場合はGNU grepの-Hを使用し、ファイル名を非表示にしたい場合は-hを使用します。

grep -nH 'listen' nginx.conf

一致行の前後の文脈も見る

エラー行だけでは原因を特定しにくい場合、-A、-B、-Cで周囲の行も合わせて確認します。数字は追加で出力する行数です。

grep -A 3 'ERROR' app.log
grep -B 2 'ERROR' app.log
grep -C 2 'ERROR' app.log

-A 3は後ろ3行、-B 2は前2行、-C 2は前後各2行を追加します。

一致した部分のみを出力する

-oは行全体ではなく、パターンと一致した部分のみを出力します。1行で複数回一致した場合、それぞれ別々の出力として表示されます。

grep -oE '[0-9]{3}-[0-9]{4}' contacts.txt

ターミナルで一致部分を強調するには--color=autoを使用できます。ファイルや他のコマンドに出力を渡す場合は、色制御文字が混ざらないようにautoまたはneverを使用してください。

ログやコマンド出力で活用する

最近のログからエラーを探す

ログ全体の代わりに最近の範囲だけを検索するにはtailと組み合わせます。

tail -n 500 app.log | grep -iE 'error|failed|fatal'

ファイルに追加される新しいログを継続的にフィルタリングするには次のように使用できます。

tail -F app.log | grep --line-buffered 'ERROR'

--line-bufferedはGNU拡張オプションで、各行が入ってくるときに出力バッファを空にしてパイプでの遅延を減らします。ログローテーションを含む追跡方法はLinux tailコマンドの使い方で確認できます。

サービスとプロセスの結果をフィルタリングする

systemctlの出力から特定のサービス名を探すことができます。

systemctl list-unit-files | grep 'nginx'

プロセスの存在の有無だけを確認する目的であれば、pgrepの方がps | grepより直接的である場合が多いです。コマンド名と引数を一緒に検索するには、次のように実行できます。

pgrep -af 'nginx'

一致行数を数える

-cは一致回数ではなく、一致した行の数を出力します。1行にパターンが複数回あっても、その行は1回だけ数えます。

grep -c 'ERROR' app.log

1行内の空でない、重なりのない一致部分を数えるには、各一致部分を-oで分割してからwc -lで数えることができます。

grep -o 'ERROR' app.log | wc -l

出力せず存在確認だけ行う

-qは結果を出力せず、終了ステータスだけを返します。シェルの条件文でパターンの存在有無を確認する場合に適しています。

if grep -q 'ready' status.log; then
  echo 'サービス準備完了'
fi

grepの終了ステータスの理解

grepは結果文字列だけでなく、終了ステータスにより検索結果を渡します。通常、一致行があれば0、一致行がなければ1、ファイルを読み取れない場合や文法に問題がある場合は2を返します。

終了ステータス 意味 スクリプトでの判断
0 1つ以上の一致がある 条件が真の場合として処理
1 一致なし 正常な検索結果である可能性がある
2 エラー発生 入力ファイル、権限、またはパターンを確認

したがって、結果がないという理由だけでコマンドの実行自体が失敗したと判断してはいけません。自動化では1と実際のエラーである2を区別する必要があります。GNU grep -qは一致が見つかると、他にエラーがあっても状態0で終了する可能性があるため、すべての入力ファイルのエラー検出が重要な場合は別途検証が必要です。

よく発生する問題と解決方法

パターンがハイフンで始まるとき

-ERRORのようなパターンはオプションと誤解される可能性があります。オプションの終わりを意味する--の後にパターンを書きます。

grep -- '-ERROR' app.log

Binary file matches メッセージが出るとき

GNU grepが入力をバイナリファイルと判断すると、一致行の代わりにメッセージしか表示しないことがあります。実際にテキストファイルであると確信がある場合は、-aでテキストとして扱うことができます。

grep -a 'ERROR' mixed-data.log

逆に再帰検索でバイナリファイルを除外したい場合は、-Iを使用できます。端末の表示や動作を乱す可能性のある制御文字が含まれることがあるため、不明なバイナリデータに無条件で-aを使わないでください。

正規表現の特殊文字により結果が異なるとき

ドットは正規表現で任意の一文字と一致し、アスタリスクは前の表現の繰り返しを意味します。単純な文字列を検索したい場合は-Fを使い、正規表現を使いたい場合はパターン全体をシングルクォートで囲み、シェルの展開を防ぎます。

再帰検索が遅すぎるか、結果が多すぎるとき

検索開始ディレクトリを絞り込み、--include、--exclude、--exclude-dirで不要なファイルを除外します。権限エラーだけを隠すために標準エラー全体を破棄すると重要な問題も見逃してしまう可能性があるため、まず検索範囲とファイル権限を確認するのが良いです。

よくある質問

grepは基本的に大文字と小文字を区別しますか?

はい。基本検索は大文字小文字を区別します。区別しないようにするには-iを使用します。ロケールによって文字の大文字小文字処理結果が異なる場合がある点も考慮する必要があります。

grep -rとgrep -Rは何が違いますか?

GNU grepでは両方とも再帰検索を行いますが、-Rは検索中に出会ったすべてのシンボリックリンクをたどります。一般的なソースや設定ファイルの検索には-rの方が予測しやすいです。

検索結果がないときはエラーですか?

必ずしもエラーではありません。一致がない場合は通常終了状態1を返し、ファイルアクセス失敗や間違ったオプションなどのエラーは状態2で区別されます。

複数の検索語のうち1つでも含まれる行はどうやって探しますか?

grep -E 'error|warning' ファイル名のように拡張正規表現の選択演算子を使用するか、grep -e 'error' -e 'warning' ファイル名のように-eを繰り返します。検索語を正規表現ではなく文字列そのままで処理するには-Fも併せて使用できます。

まとめ

一般的な文字列検索はgrep -F、複数の正規表現条件はgrep -E、ディレクトリ全体の検索はgrep -rを基準に覚えるとよいです。結果を解釈しやすくするには-nと-C、ファイル一覧のみが必要な場合は-l、スクリプトで存在確認のみしたい場合は-qを活用できます。

パターンはシングルクォートで囲み、再帰検索範囲を具体的に制限し、終了状態1とエラー状態2を区別することが安全な使用のポイントです。他の基本ツールも併せて確認したい場合はLinuxでよく使うコマンド一覧を参照してください。