Bash 入門

正規表現

正規表現(Regular expressions)は、通常「regex」または「regexp」と略され、テキスト内でのパターンマッチングを行うための強力なツールです。特定のパターンに一致するテキスト文字列を「検索(サーチ)」、「検索と置換(リプレイス)」、あるいは「バリデーション(マッチング)」するための簡潔で柔軟な手法を提供します。

正規表現をマスターすることで、効率的なテキスト処理能力を解放できます。これはデータバリデーション、抽出、ログ解析、コードのリファクタリングといったタスクを処理するための鍵となります。その構文は一見すると難解に感じるかもしれませんが、基本概念さえ理解してしまえば、あらゆるアプリケーションシーンでその絶大な威力を発揮できるようになります。本章では、正規表現の全体像を紹介し、後続の章で使用する grepsedawk などのツールを活用するための堅牢な基礎を築きます。

1. 正規表現の基本構文

正規表現は、リテラル文字(literal characters)と特殊文字(通常「メタ文字(metacharacters)」と呼ばれます)で構成されます。リテラル文字はそれ自体にマッチし、メタ文字は複雑なパターンマッチングを実現するための特殊な意味を持ちます。まずは基本的なビルディングブロックを探索してみましょう。

1.1 リテラル文字 (Literal Characters)

最も単純な正規表現はリテラル文字のみで構成されます。例えば、正規表現 hello は文字列 "hello" に完全に一致します。ケースセンシティブ(大文字・小文字の区別)は非常に重要です。デフォルトでは Hellohello にマッチしません(ただし、次章の grep で紹介するように、大文字・小文字を区別せずにマッチさせるオプションも存在します)。

例:
正規表現 bash は、以下の文字列内の "bash" にマッチします:

  • "Bashスクリプトが大好きです。" (I love bash scripting.)
  • "Bashシェルは非常に強力です。" (The bash shell is powerful.)

以下の場合はマッチしません:

  • "BASH scripting is fun." (大文字・小文字が異なるため)
  • "I use zsh." (リテラル文字が異なるため)

1.2 メタ文字 (Metacharacters)

メタ文字は正規表現の強力な機能の核心です。以下は習得必須のメタ文字です:

  • . (ドット / Dot): 改行記号を除く任意の1文字にマッチします。
    • 例: 正規表現 a.c
      • マッチ: "abc", "a1c", "a c"
      • アンマッチ: "ac" (文字が足りない), "abbc" ("a" と "c" の間に1文字より多く存在する), "a\nc" (改行記号)
  • ^ (カレット / Caret): 行頭にマッチします。
    • 例: 正規表現 ^hello
      • マッチ: "hello world" ("hello" が行頭にあるため)
      • アンマッチ: "world hello", " hello" (前方にスペースがあるため)
  • $ (ドル記号 / Dollar): 行末にマッチします。
    • 例: 正規表現 world$
      • マッチ: "hello world" ("world" が行末にあるため)
      • アンマッチ: "world hello", "world " (末尾にスペースがあるため), "world is great"
  • [] (文字クラス / Character Class): 括弧内の任意の1文字にマッチします。範囲指定も可能です。
    • 例:
      • [aeiou] は、小文字の母音いずれか1文字 ("a", "e", "i", "o", "u") にマッチします。
      • [0-9] は、任意の数字1文字 ("0", "1", "9") にマッチします。
      • [a-zA-Z] は、小文字または大文字のアルファベット1文字 ("a", "Z") にマッチします。
    • 正規表現 [abc]
      • マッチ: "a", "b", "c"
      • アンマッチ: "d", "ab" (1文字のみにマッチするため)
  • [^] (否定文字クラス / Negated Character Class): 括弧内に含まれない任意の1文字にマッチします。
    • 例: 正規表現 [^0-9] は、数字以外の任意の1文字にマッチします。
      • マッチ: "a", " " (スペース), "$"
      • アンマッチ: "0", "5"
  • \ (バックスラッシュ / Backslash): メタ文字をエスケープし、リテラル文字として扱います。
    • 例: 正規表現 \. は、リテラルとしてのドット (.) にマッチします。バックスラッシュがない場合、. は「任意の文字」を意味してしまいます。
      • マッチ: "file.txt"
      • アンマッチ: "fileatxt"

1.3 量化子 (Quantifiers)

量化子は、直前の要素が出現する回数を指定するために使用されます。

  • * (アスタリスク / Asterisk): 直前の要素が0回以上出現する場合にマッチします。
    • 例: 正規表現 ab*c
      • マッチ: "ac" ('b' が0回), "abc" ('b' が1回), "abbc" ('b' が2回), "abbbbbbc"
      • アンマッチ: "adc" ('b' が存在せず、他の文字が含まれているため)
  • + (プラス / Plus): 直前の要素が1回以上出現する場合にマッチします。
    • 例: 正規表現 ab+c
      • マッチ: "abc" ('b' が1回), "abbc", "abbbbbbc"
      • アンマッチ: "ac" ('b' が0回), "adc"
  • ? (クエスチョンマーク / Question Mark): 直前の要素が0回または1回出現する場合にマッチします。
    • 例: 正規表現 ab?c
      • マッチ: "ac", "abc"
      • アンマッチ: "abbc" ('b' が2回), "adc"
  • {n}: 直前の要素がちょうど n 回出現する場合にマッチします。
    • 例: 正規表現 a{3}b
      • マッチ: "aaab"
      • アンマッチ: "aab", "aaaab"
  • {n,}: 直前の要素が n 回以上出現する場合にマッチします。
    • 例: 正規表現 a{2,}b
      • マッチ: "aab", "aaab", "aaaaaaaab"
      • アンマッチ: "ab"
  • {n,m}: 直前の要素が n 回から m 回の間(n と m を含む)出現する場合にマッチします。
    • 例: 正規表現 a{2,4}b
      • マッチ: "aab", "aaab", "aaaab"
      • アンマッチ: "ab", "aaaaab"

1.4 アンカー (Anchors)

アンカー(^$ など)自体は文字にマッチするのではなく、文字列内の「位置」にマッチします。

  • \b: 単語境界(単語構成文字と非単語構成文字の間の位置)にマッチします。単語構成文字は通常、アルファベット、数字、アンダースコアです。
    • 例: 正規表現 \bcat\b
      • マッチ: "cat" (独立した単語として), " cat ", "cat."
      • アンマッチ: "category", "tomcat"
    • 解説:\b を使用することで、他の単語の一部ではなく、完全な単語としての "cat" のみをマッチさせることができます。

1.5 グループ化と論理和 (Grouping and Alternation)

  • () (括弧 / Parentheses): 正規表現の複数の部分を一つにグループ化します。これにより、量化子などの操作をグループ全体に適用できます。また、「キャプチャグループ」を作成し、後で参照することも可能です(詳細は sed の章で解説します)。
    • 例: 正規表現 (ab)+
      • マッチ: "ab", "abab", "ababab"
      • アンマッチ: "a", "b", "ac"
  • | (パイプ / Pipe): 論理和(OR)を表します。パイプの前または後の式のいずれかにマッチします。
    • 例: 正規表現 cat|dog
      • マッチ: "cat", "dog"
      • アンマッチ: "bird", "catdog" ("cat" または "dog" のどちらかにマッチするものであり、連続出現を意味しないため)

1.6 文字クラスの省略記法

よく使われる文字クラスには省略記法が存在します:

  • \d: 任意の数字にマッチ([0-9] と同等)。
  • \D: 任意の非数字にマッチ([^0-9] と同等)。
  • \w: 任意の単語構成文字にマッチ(アルファベット、数字、アンダースコア。[a-zA-Z0-9_] と同等)。
  • \W: 任意の非単語構成文字にマッチ([^a-zA-Z0-9_] と同等)。
  • \s: 任意の空白文字(スペース、タブ、改行など)にマッチ。
  • \S: 任意の非空白文字にマッチ。

例: 正規表現 \d+

    • マッチ: "1", "123", "1234567890"
    • アンマッチ: "a", "abc"

2. 正規表現の実践例

学んだ概念を組み合わせて、実戦的な例を見てみましょう:

YYYY-MM-DD 形式の日付にマッチさせる:

\d{4}-\d{2}-\d{2}

解説: この正規表現は、4つの数字 (\d{4})、ハイフン、2つの数字 (\d{2})、ハイフン、最後に2つの数字 (\d{2}) の順にマッチします。

メールアドレスにマッチさせる(簡易版):

\w+@\w+\.\w+

解説: 1つ以上の単語構成文字 (\w+)、@ 記号、1つ以上の単語構成文字 (\w+)、ドット (\.)、最後に1つ以上の単語構成文字 (\w+) にマッチします。
注:これは極めて簡略化された例であり、すべての有効なメールアドレス形式をカバーしているわけではありません。堅牢なバリデーションにはより複雑な式が必要です。

"Error" で始まる行にマッチさせる(ケースインセンシティブ):

^Error

解説: grep で大文字・小文字を区別しないようにするには、次章で学ぶように -i フラグを使用します:grep -i "^error"

(XXX) XXX-XXXX 形式の電話番号にマッチさせる:

\(\d{3}\) \d{3}-\d{4}

解説: エスケープされた左括弧 \(( はメタ文字のため)、3つの数字 (\d{3})、エスケープされた右括弧 \)、スペース、3つの数字 (\d{3})、ハイフン、最後に4つの数字 (\d{4}) にマッチします。

3. 具体的な活用シーン

正規表現はソフトウェア開発、システム管理、データ分析において広く使用されています。以下にいくつかの例を挙げます:

  • ログ解析: ログファイルを分析して特定のエラーメッセージやパターンを探し、システムの問題を特定します。例えば、ログから "error" という単語を含むすべての行を抽出する場合などです。
  • データバリデーション: フォームでのユーザー入力を検証し、メールアドレス、電話番号、日付などが特定のフォーマットに準拠しているか確認します。
  • コードのリファクタリング: 正規表現を使用してコードパターンを検索・置換します。変数のリネームや関数呼び出しの更新などに役立ちます。
  • データ抽出: 非構造化テキストから特定のデータを抽出します。例えば、Webサイトから製品価格のみを抜き出すといったケースです。
  • セキュリティ防御: 侵入検知システム(IDS)は、ネットワークトラフィック内の悪意あるパターンを識別するために正規表現を使用します。

「オートメーションシステム管理タスク」のケーススタディにおいて、正規表現は構成ファイル(コンフィグファイル)のバリデーションに応用できます。例えば、ネットワーク設定ファイル内のすべての IP アドレスが正当であることを保証する必要がある場合、正規表現を使えば各 IP アドレスが正しい形式(ドットで区切られた 0 から 255 までの4つの数字のグループ)に合致するかを瞬時にチェックできます。