Linux における grep を使用したテキスト検索

CompTIABeginner
オンラインで実践に進む

はじめに

この実験では、強力な grep コマンドを使用して、Linux システム内のファイルからテキストを効率的に検索する方法を学びます。まずは、単一または複数のファイルから特定の文字列を検索する基本操作から始め、grep がどのように一致した行を表示し、複数の場所を検索する際にソースファイルをどのように識別するかを理解します。

この基礎の上に、検索をより洗練させるための高度な機能を探求します。コンテキストを把握するための行番号の表示、行の先頭や末尾のパターンに一致させる ^$ などのアンカーの使用、そして複雑で柔軟なパターンマッチングを可能にする基本正規表現と拡張正規表現の両方の機能を活用する方法を習得します。

grep によるファイル内の基本検索

このステップでは、ファイル内で基本的な検索を行うための grep コマンドの根本的な使い方を学びます。grep (Global Regular Expression Print) コマンドは、1 つ以上のファイルから特定の文字列やパターンを検索し、それを含む行を表示するために使用される強力なコマンドラインユーティリティです。

grep の基本構文は次の通りです:grep PATTERN [FILE...]

まずは簡単なタスクから始めましょう。システムのユーザーデータベースファイルから、現在のユーザーである labex に関する情報を探します。この情報は /etc/passwd ファイルに保存されています。

ターミナルで次のコマンドを実行し、/etc/passwd ファイル内で文字列 labex を含む行を検索してください。

grep labex /etc/passwd

ユーザー名 labex を含むファイル内の出力行が表示されるはずです。

labex:x:5000:5000::/home/labex:/usr/bin/zsh

grep コマンドは、複数のファイルを同時に検索することもできます。次に、3 つの重要なシステム設定ファイル(/etc/passwd、セキュアなユーザーアカウント情報が保存されている /etc/shadow、ユーザーグループを定義する /etc/group)から文字列 labex を検索してみましょう。

/etc/shadow ファイルには機密情報が含まれているため、読み取るには管理者権限が必要です。sudo コマンドを使用して、これらの権限で grep を実行できます。labex ユーザーは、パスワードなしで sudo アクセスができるよう設定されています。

次のコマンドを実行して、3 つすべてのファイルから labex を検索します。

sudo grep labex /etc/passwd /etc/shadow /etc/group

複数のファイルを検索する場合、grep は一致した各行の先頭に、その一致が見つかったファイル名を付加することに注目してください。

/etc/passwd:labex:x:5000:5000::/home/labex:/usr/bin/zsh
/etc/shadow:labex:$y$j9T$L6UYJUCu2XytrdFToEOw.1$yp2xAOVTbIPmbABMnS/xDsyce7xayU80JgIs3lrqw4B:20265:0:99999:7:::
/etc/group:sudo:x:27:labex
/etc/group:ssl-cert:x:121:labex
/etc/group:labex:x:5000:
/etc/group:public:x:5002:labex

これにより、これら 3 つのファイルにまたがるユーザー labex に関連するすべての行が表示されます。

-n オプションによる行番号の表示

このステップでは、一致が見つかった行番号を表示することで grep の出力を強化する方法を学びます。これは、編集や詳細な分析のために大きなファイル内のパターンを特定する必要がある場合に特に便利です。-n オプションを使用すると、grep は出力の各行の先頭に入力ファイル内の対応する行番号を付加します。

前のステップのコマンドを応用してみましょう。3 つのシステムファイルからユーザー labex を検索しました。今度は同じ検索を行いながら、各一致の行番号も表示します。

前のステップで実行したコマンドに -n オプションを追加します。制限のある /etc/shadow ファイルにアクセスするため、引き続き sudo を使用することを忘れないでください。

ターミナルで次のコマンドを実行します。

sudo grep -n labex /etc/passwd /etc/shadow /etc/group

以前と同様の出力が表示されますが、今回は各行の先頭にファイル名と一致した行番号がコロンで区切られて表示されます。

/etc/passwd:32:labex:x:5000:5000::/home/labex:/usr/bin/zsh
/etc/shadow:32:labex:$y$j9T$L6UYJUCu2XytrdFToEOw.1$yp2xAOVTbIPmbABMnS/xDsyce7xayU80JgIs3lrqw4B:20265:0:99999:7:::
/etc/group:21:sudo:x:27:labex
/etc/group:60:ssl-cert:x:121:labex
/etc/group:61:labex:x:5000:
/etc/group:62:public:x:5002:labex

出力内の 323221606162 といった数字に注目してください。これらが行番号です。例えば、文字列 labex/etc/passwd の 32 行目と /etc/shadow の 32 行目で見つかったことがわかります。このシンプルなオプションにより、grep はファイルの内容を把握し、ナビゲートするためのさらに効果的なツールになります。

^ と $ アンカーによる行位置の指定

このステップでは、アンカーの使用方法を学ぶことで grep のスキルを向上させます。アンカーは正規表現における特殊文字で、文字そのものではなく、行内の「位置」に一致します。これにより、より具体的で強力な検索パターンを作成できます。最も一般的な 2 つのアンカーは以下の通りです。

  • ^ (カレット): 行の先頭に一致します。
  • $ (ドル記号): 行の末尾に一致します。

/etc/passwd ファイルを使用して、これらがどのように機能するか見てみましょう。

まず、/etc/passwd 内の文字列 root を単純に検索してみます。

grep root /etc/passwd

他のエントリに "root" という文字列が含まれている可能性があるため、出力には複数の行が表示される場合があります。

root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

ここで、検索を絞り込んでみましょう。/etc/passwd ファイルでは、各レコードの最初のフィールドがユーザー名です。root ユーザー専用のユーザーレコードを見つけるには、^ を使用して検索を行の先頭に固定(アンカー)します。

次のコマンドを実行してください。パターン ^root は、root始まる 行のみに一致するよう grep に指示します。

grep ^root /etc/passwd

今回は出力が非常に具体的になり、root ユーザーの行のみが表示されます。

root:x:0:0:root:/root:/bin/bash

次に、行末アンカー $ を使用してみましょう。/etc/passwd レコードの最後のフィールドは、ユーザーのデフォルトのログインシェルを指定します。これを利用して、デフォルトシェルとして /bin/bash を使用しているすべてのユーザーを見つけることができます。

パターン bash$ は、文字列 bash終わる すべての行に一致します。

grep bash$ /etc/passwd

このコマンドは、/bin/bash が割り当てられたシェルであるすべてのユーザーエントリを表示します。

root:x:0:0:root:/root:/bin/bash

(注:システム上の他のユーザーもデフォルトシェルとして bash を使用している場合、出力結果は異なる場合があります。)

^$ アンカーを使用することで、検索結果を大幅に絞り込み、探しているものを正確に見つけることができます。

基本正規表現によるパターンマッチング

このステップでは、grep で基本正規表現 (BRE: Basic Regular Expressions) を使用して、より柔軟な検索パターンを作成する方法を探ります。BRE では、メタ文字と呼ばれる特定の文字が、その文字通りの意味を超えた特別な意味を持ちます。これにより、固定された文字列だけでなく、パターンに一致させることができます。

ここでは、2 つの基本的なメタ文字 * (アスタリスク) と . (ドット) について説明します。

まず、アスタリスク (*) を見てみましょう。このメタ文字は、直前の文字の 0 回以上の繰り返しに一致します。実際に動作を確認するために、次のコマンドを実行してください。シェルが * をファイルのワイルドカードとして展開しようとするのを防ぎ、リテラルパターンとして扱うように、パターンをシングルクォート ('roo*') で囲みます。

grep 'roo*' /etc/passwd

出力にはおそらく複数の行が表示されます。

root:x:0:0:root:/root:/bin/bash
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
systemd-timesync:x:104:110:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
rtkit:x:108:113:RealtimeKit,,,:/proc:/usr/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

この結果を分析してみましょう。パターン 'roo*' は、ro の後に 0 個以上の o が続く行を検索します。

  • root 行は、roo (ro の後に 1 つの o) を含んでいるため一致します。
  • proxy 行は、"proxy" 内に ro (ro の後に 0 個の o) を含んでいるため一致します。
  • systemd-timesync 行は、"Synchronization" 内に ro を含んでいるため一致します。
  • rtkit 行は、"proc" 内に ro を含んでいるため一致します。
  • operator 行は、"operator" と "/root" の両方に ro を含んでいるため一致します。

次に、ドット (.) メタ文字を見てみましょう。ドットは任意の 1 文字に一致します。次のコマンドを実行して、動作がどのように異なるかを確認してください。

grep 'ro.' /etc/passwd

今回は、次のような一致が表示されます。

root:x:0:0:root:/root:/bin/bash
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
systemd-timesync:x:104:110:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
rtkit:x:108:113:RealtimeKit,,,:/proc:/usr/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

パターン 'ro.' は、ro の後に正確に 1 文字の何らかの文字が続く行を検索します。

  • root 行は、"root" 内で ro の後に o が続くため一致します。
  • proxy 行は、"proxy" 内で ro の後に x が続くため一致します。
  • systemd-timesync 行は、"Synchronization" 内で ro の後に n が続くため一致します。
  • rtkit 行は、"proc" 内で ro の後に c が続くため一致します。
  • operator 行は、"operator" と "/root" 内で ro の後に別の文字が続くため一致します。

出力を比較することで、正規表現の威力を明確に理解できます。'roo*''ro.' の両方のパターンが複数の行に一致していますが、異なるメタ文字を使用することで、さまざまな方法で検索を微調整できることがわかります。

拡張正規表現による複雑な検索

このステップでは、拡張正規表現 (ERE: Extended Regular Expressions) を使用して、さらに複雑で強力な検索を行う方法を学びます。ERE は、基本正規表現 (BRE) よりも豊富なメタ文字セットを提供します。ERE を有効にするには、grep -E コマンド、またはその伝統的なエイリアスである egrep を使用します。現在では grep -E を使用するのがより現代的で推奨される方法です。

まず、量指定子(Quantifiers)について見てみましょう。ERE では、波括弧 {} を使用して文字が出現する正確な回数を指定できます。例えば、小文字の 'o' が正確に 2 つ連続している行を見つけるには、パターン o{2} を使用します。

次のコマンドを実行してください。シェルが特殊文字を誤解しないように、パターンをシングルクォートで囲みます。

grep -E 'o{2}' /etc/passwd

"oo" を含む複数の行が表示されます。

root:x:0:0:root:/root:/bin/bash
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

このコマンドが機能するのは、パターン o{2} が "root" や "spool" などのエントリに見られる 2 つ連続した 'o' 文字に具体的に一致するためです。

次に、選択(Alternation)を見てみましょう。この強力な ERE 機能を使用すると、'OR' 演算子として機能するパイプ記号 | を使って、複数の候補パターンのいずれかを検索できます。

例えば、root または Root のいずれかのユーザーレコードを探したい場合(大文字小文字が不明な場合など)、次のコマンドを使用できます。

grep -E 'root|Root' /etc/passwd

このコマンドは、文字列 root または文字列 Root のいずれかを含む行を検索します。出力は以下の通りです。

root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

root ユーザーの行と operator ユーザーの行の両方が一致します。これは、両方に小文字の "root" 文字列が含まれているためです。

grep -E で有効になる拡張正規表現は、複雑な検索パターンを作成するためのより表現力豊かで強力な構文を提供し、grep をテキスト処理に不可欠なツールにします。

まとめ

この実験では、Linux で基本的なテキスト検索を行うための grep コマンドの使用方法を学びました。まず、単一ファイル内での特定の文字列の基本検索から始め、次に複数ファイルにまたがる検索へと拡張し、grep が一致した行に対応するファイル名をどのように付加するかを確認しました。また、ファイル内のパターンを特定するのに役立つ、各一致の行番号を表示する -n オプションの使用方法も学びました。

さらに、行の先頭 (^) または末尾 ($) のテキストを検索するためのアンカーを使用して、より高度なパターンマッチング機能を探索しました。実験は、基本正規表現と拡張正規表現の両方の使用へと進み、ファイル内の特定の情報を見つけるための、より複雑で強力な検索パターンを構築できるようになりました。