🐧 Linux 総合学習プラットフォーム
正規表現・テキスト処理 ・ 中級

grep で行を検索する

grep はファイルや標準入力から、パターンに一致する行を取り出すコマンドです。grep "パターン" ファイル の形で使い、よく使うオプションに大文字小文字を無視する -i、一致しない行だけ出す -v、一致した件数を数える -c、行番号を付ける -n があります。-r を付ければディレクトリ以下を再帰的に検索できます。パイプと組み合わせ、別コマンドの出力から必要な行だけを絞り込む使い方も定番です。

正規表現をいくら覚えても、それを実際に走らせる相手がいなければ宝の持ち腐れだ。その最初の相手が grep である。

grep は「ファイルや標準入力の中から、パターンに一致する行を抜き出して表示する」コマンドだ。名前は global regular expression print の頭文字に由来する。

🔗
たとえgrep は、本のページを次々めくって付箋を貼る助手のようなものだ。条件に合う行だけを拾い、それ以外は黙って通り過ぎる。

基本の形は grep 'パターン' ファイル で、指定したファイルの各行を上から順に調べ、パターンに一致した行だけを画面に出す。

パターンには前の項目で学んだ正規表現がそのまま使え、ここでは grep や sed が既定とする基本正規表現(BRE)の方言で解釈される。

「探す」という最も基本的な操作を担うため、テキスト処理の入り口として絶え間なく使うコマンドだ。まずは手を動かす形から入ろう。

⌨ いちばん最初に打つ一行は

ファイルの各行root:x:0...daemon:...bin:x:2...sys:x:3...grep^rootroot:x:0...全行を上から調べ、一致した行だけを出す

たとえば grep '^root' /etc/passwd と打つと、/etc/passwd の中から root で始まる行だけが表示され、root:x:0:0:root:/root:/bin/bash のような行が返る。

grep '^root' /etc/passwd ……root で始まる行だけを表示する。bash$ なら bash で終わる行、^r..t なら r と t のあいだが任意2文字の行を選べる。

bash$ /etc/passwd のように $ を使えば bash で終わる行を、^r..t なら r と t のあいだが任意の2文字の行を選べる。

ここでもパターンはシングルクォートで囲むのが鉄則だ。^ $ * といった記号をシェルに先取りされないためで、囲み忘れると意図しない展開やエラーの原因になる。

ファイル名を省略してパイプ | からの入力に対して使うこともでき、その場合は別コマンドの出力を絞り込むフィルタとして働く。この「フィルタとして使える」性質が、後でパイプラインを組むときに効いてくる。

🔠 大文字小文字の混在や、除外はどうする

grep は組み合わせるオプションで使い勝手が大きく変わる。

-i は大文字小文字を区別せず探す(ignore case)。ログには ERROR と error が混在しがちなので、grep -i 'error' app.log とすればどちらも拾える。

-v は条件を反転し、一致しない行だけを残す(invert)。grep -v '^#' file はコメント行を除いて実効行だけを見る定番で、空行も消したいなら grep -v '^#' file | grep -v '^$' のようにつなげる。

grep -i 'error' app.log で大小無視。grep -v '^#' file でコメント行を除外。-c で件数、-n で行番号を付ける。

-c は一致した行数を数え(count)、-n は各行の先頭に行番号を付ける(number)。

ここで一つ罠がある。-c が数えるのは「一致した行の数」であって「出現回数」ではない点だ。1行に同じ語が3回出ても、-c はその行を1と数える。この勘違いは件数集計のずれとして後で効いてくるので、早めに正しておこう。

つまずき-c が数えるのは「一致した行の数」で、「出現回数」ではない。1行に同じ語が3回出ても、-c はその行を1と数える。

📁 どのファイルに、その語があるのか

-r を付けると、指定したディレクトリ以下を再帰的にたどって検索する(recursive)。grep -r 'PermitRootLogin' /etc/ssh/ のように使い、見つかった「ファイル名:一致行」が並ぶ。

さらに -l(小文字のエル)を足すと中身は出さず、該当したファイル名だけを一覧でき(list)、grep -rl 'nameserver' /etc/ のように「どの設定ファイルにこの語があるか」を探すときの王道だ。

これらのオプションは grep -rin 'timeout' . のようにまとめて組み合わせて使え、現在地以下を大文字小文字を無視しつつ行番号付きで再帰検索する、といった一行が日常的に役立つ。

コツ-r -l -i -n はまとめて組み合わせられる。grep -rin 'timeout' . で、現在地以下を大小無視・行番号付きで再帰検索できる。

部分一致の暴発を防ぐには -w が役立つ。grep 'cat' words.txt は category や locate の中の cat まで拾うが、grep -w 'cat' は前後が区切りのときだけ一致させ、独立した単語 cat だけを残す。

語そのものを探したいのに似た語まで混ざってしまうときは、-w を思い出してほしい。

🪓 行ではなく、当たった断片だけが欲しいときは

-o は、行全体ではなくパターンに当たった断片だけを1行ずつ出力する(only matching)。

ログからIPアドレスらしき並びだけを抜き出す例が分かりやすく、grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' access.log と書けば、192.168.1.10 のような一致部分だけが縦に並ぶ。

ここで -E を併用しているのは、+ という量指定子をエスケープなしで使うためだ(次の項目で詳しく扱う)。

つまずきgrep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' は「形がIPに似た文字列」を拾うだけ。999.999.999.999 のような実在しない値も一致するので、厳密な検証は別途必要だ。

なお、この式は「形がIPに似た文字列」を拾うだけで、999.999.999.999 のような実在しない値も一致してしまうため、厳密な値の検証は別途必要だ、という限界も覚えておくとよい。

-o は、行ではなく「中の断片」を集めたいときの専用スイッチだ。

⚠ つまずいたら、まずこれ

失敗として多いのは、パターンをクォートで囲み忘れて $ や * がシェルに解釈されてしまうこと、そして -c を「出現回数」と誤解することだ。

また BRE のまま grep 'a+' と書いて + が量指定子として効かず一致しない、というのも頻出で、これは次の項目の -E で解決する。

検索結果が0件のとき、grep は終了ステータスとして非ゼロを返すので、スクリプトの中で if grep -q 'pattern' file; then … のように「一致したかどうか」だけを条件分岐に使うこともできる。-q は何も表示せず結果だけを返すオプションで、存在チェックに重宝する。

コツ-q は何も表示せず結果だけを返す。if grep -q 'pattern' file; then … のように「一致したかどうか」を条件分岐に使え、存在チェックに重宝する。

実務では、grep の真価はパイプと組み合わせたときに発揮される。ps aux | grep 'nginx' で動いているプロセスを絞ったり、設定の塊から grep で必要な行だけを取り出してから sed や awk にさらに渡したり、grep 'error' app.log | wc -l で件数を数えたりと、調査と集計の起点になる。

前後の文脈もあわせて見たいときは -A(後ろ)-B(前)-C(前後)で一致行の周辺も表示でき、grep -C2 'error' app.log のようにエラーの前後2行まで確認できる。

「まず grep で行を絞り、必要ならパイプで次の道具へ渡す」。この流れが、正規表現を使った作業の基本リズムだ。

この項目に出てくる用語

正規表現せいきひょうげん
文字列のパターンを記号で表す書き方。検索や置換に使う。
基本正規表現(BRE)きほんせいきひょうげん
grep や sed の既定方言。+ ? { } ( ) | に \ が必要。

関連コマンド

grep

▶ 学習アプリでこの続きを学ぶ・演習する