量指定子で繰り返しを表す
直前のパターンが何回繰り返されるかを表すのが「量指定子」です。* は0回以上、+ は1回以上、? は0回または1回(あってもなくてもよい)を意味します。回数を細かく指定したいときは {n} でちょうどn回、{n,} でn回以上、{n,m} でn〜m回と書けます。例えば ab* は a の後に b が0個以上、go+gle は o が1個以上、colou?r は color と colour の両方にマッチします。+ ? { } は基本の正規表現では \ が必要になる点に注意します。
ここまでで、1文字を指す道具(. や文字クラス)を学びました。しかし実際のパターンでは「直前の文字が何回くり返されるか」を表したい場面がほとんどです。数字が何桁続くか分からない、空白が1個か複数か分からない、ある文字があってもなくてもよい——こうした「回数」を表すのが量指定子です。量指定子は単独では使えず、必ず直前のパターン(1文字や文字クラス、グループ)に対して「それを何回くり返すか」を指定する形で働きます。1文字を指す道具と回数を指す道具を組み合わせることで、正規表現は一気に表現力を増します。
基本の3つ * + ?
もっとも基本的な量指定子は * + ? の3つです。* は0回以上のくり返しを表し、「あってもなくてもよく、何個でもよい」という最も緩い指定です。+ は1回以上、つまり「最低1個は必要で、何個でもよい」を表します。? は0回または1回、すなわち「あってもなくてもよいが、多くても1個」を意味します。違いを具体例で見ると、ab* は a の後ろに b が0個以上なので a, ab, abb… に一致し、go+gle は o が1個以上必要なので gogle, google, gooogle に一致しますが、o が無い ggle には当たりません。colou?r は u が0個か1個なので、color と colour の両方にちょうど一致します。この3つの違い(0以上・1以上・0か1)を取り違えると、拾いたいものを取りこぼしたり、余計なものを拾ったりするので、最初に丁寧に区別しておきましょう。
回数を細かく指定する波かっこ
「ちょうど何回」「何回以上」「何回から何回まで」と厳密に指定したいときは、波かっこ { } を使います。{n} はちょうどn回、{n,} はn回以上、{n,m} はn回からm回までを表します。たとえば [0-9]{4} は「数字がちょうど4個」で、西暦の年号やコードの桁数チェックに使えます。echo '西暦2026年と12月' から4桁を拾う例なら、一致するのは2026だけで、2桁の12は当たりません。[0-9]{2,4} なら2個から4個、[0-9]{2,} なら2個以上です。a{3} は aaa にちょうど一致します。回数が決まっている入力の検証では、この波かっこが正確で読みやすい武器になります。じつは * + ? は波かっこで言い換えることもでき、* は {0,}、+ は {1,}、? は {0,1} と同じ意味です。こう並べてみると、3つの基本記号がそれぞれ「回数のよくある型」に名前を付けたものだと分かり、量指定子全体を一つの考え方として整理できます。
方言による \ の要否に注意
ここで一つ、つまずきやすい落とし穴があります。+ ? { } は、grep や sed が既定で使う基本正規表現(BRE)では、そのままだと特別な意味を持たず、ただの文字として扱われます。BRE でこれらを量指定子として使うには、直前にバックスラッシュを付けて \+ \? \{ \} と書く必要があります。たとえば BRE で「a が1回以上」を表すには echo 'aaa' | grep -o 'a\+' と書き、grep -o 'a+' と書くと + はただの文字になって「a に続くプラス記号」を探してしまい、何も一致しません。一方、後の項目で扱う拡張正規表現(grep -E)では、これらをエスケープなしで a+ や a{2,4} と書けます。* . ^ $ [ ] の基本記号はどちらの方言でも同じなので、まずはそこを共通の土台と考えてよいでしょう。
貪欲マッチという罠
もう一つ知っておきたいのが、* や + は既定で「できるだけ長く」一致しようとする性質です。これを貪欲(greedy)マッチと呼びます。たとえば <a>X</a><b>Y</b> という文字列に <.*> を当てると、最初の < から最後の > まで丸ごと一致してしまい、タグ1個だけをうまく取り出せません。狙った範囲で止めたいときは、<[^>]*> のように「> 以外をくり返す」と書いて、次の区切りで自然に止まるようにするのが定番のテクニックです。この「区切り文字以外をくり返す」という発想は、カンマ区切りの1項目を取るときの [^,]* など、さまざまな場面で応用が効きます。なお PCRE(grep -P)が使える環境なら .*? という非貪欲指定で「できるだけ短く」一致させることもできますが、移植性は落ちます。sed の置換で「思ったより広い範囲が消えた・置き換わった」というときは、まずこの貪欲マッチを疑うと原因にたどり着けます。
よくある失敗と実務の使いどころ
失敗として多いのは、+ と * の混同です。たとえば空白で区切られた値を扱うとき、区切りを ' *'(空白0個以上)と書くと空白が無くても一致してしまい、' +'(空白1個以上)と意図が変わります。また BRE と ERE で \ の要否が逆になることを忘れ、grep 'a{2}' のように書いて当たらない、というのも頻出のつまずきです。もう一つ見落としやすいのが、量指定子は「直前の1つ」にしか効かないという原則です。abc+ は「abc のくり返し」ではなく「ab に続いて c が1個以上」を意味し、まとまり全体をくり返したいなら (abc)+ のようにグループ化が要ります。実務では、量指定子は入力の形式検証(年号やコードの桁数チェック)、ログからの抽出(連続する数字や英字の並びを取る)、空白の正規化(連続する空白を1つにまとめる置換)など、至るところで使う正規表現の心臓部です。たとえば「行末の余分な空白を消す」なら sed -E 's/ +$//'、「連続する空白を1つにまとめる」なら sed -E 's/ +/ /g' のように、量指定子が置換の対象を柔軟に表現してくれます。「* は0以上、+ は1以上、? は0か1、{n,m} で回数指定、BRE では \ が要る」——この対応を押さえておけば、狙ったくり返しを過不足なく書けるようになります。