はじめに
awkはテキスト処理に特化した強力なツールですが、初学者がつまずきやすいポイントのひとつがmatch関数と正規表現の扱いです。特に、単純な検索だけでなく「どこにマッチしたのか」「どれくらいの長さなのか」といった情報を扱う場面では、理解が曖昧なままだと応用が効きません。
本記事では、組み込み変数RSTARTとRLENGTHの仕組みから、~演算子との違い、ループ処理への応用、日本語処理やパフォーマンス改善まで、実務で役立つ形で整理します。読み進めることで、単なる文字列検索から一歩進んだ実践的なテキスト処理ができるようになることを目指します。
参考元: GNU awk
組み込み変数RSTARTとRLENGTHの役割と仕組み
ファイル作成
cat << 'EOF' > input.txt
Hello 123 World
abc456def
no numbers here
EOF
実行コマンド
awk '{ if (match($0, /[0-9]+/)) print $0, "-> RSTART=" RSTART ", RLENGTH=" RLENGTH }' input.txt
実行結果
Hello 123 World -> RSTART=7, RLENGTH=3
abc456def -> RSTART=4, RLENGTH=3
仕組み
| 項目 | 内容 |
|---|---|
| match関数 | 文字列から正規表現に一致する位置を検索 |
| RSTART | マッチした開始位置(1始まり) |
| RLENGTH | マッチした文字列の長さ |
| マッチなし | RSTART=0、RLENGTH=-1 |
| 更新タイミング | match実行時に自動更新 |
解説
match関数は一致位置と長さを内部変数に格納し、後続処理で再利用できる点が重要です。
これにより、部分文字列の抽出や位置ベースの処理が簡潔に書けます。
matchと~演算子(正規表現マッチ)の決定的な違いと使い分け
ファイル作成
cat << 'EOF' > input.txt
apple 123
banana abc
cherry 456def
date 789
EOF
実行コマンド
awk '{ if (match($0, /[0-9]+/)) print $0, "-> match at", RSTART, "length", RLENGTH }' input.txt
実行結果
apple 123 -> match at 7 length 3
cherry 456def -> match at 8 length 3
date 789 -> match at 6 length 3
実行コマンド
awk '{ if ($0 ~ /[0-9]+/) print $0 }' input.txt
実行結果
apple 123
cherry 456def
date 789
仕組み
| 項目 | match 関数 | ~ 演算子 |
|---|---|---|
| 役割 | 正規表現の位置・長さを取得 | 正規表現にマッチするか判定 |
| 戻り値 | マッチ位置(0なら不一致) | 真(1)/偽(0) |
| 追加情報 | RSTART, RLENGTH が使える | なし |
| 用途 | 位置や部分文字列の解析 | 単純な条件分岐 |
| 柔軟性 | 高い | シンプル |
解説
match は「どこにマッチしたか」まで扱える解析向き、~は「マッチするかだけ」を見る条件分岐向きです。
用途で使い分けるのが基本です。
正規表現のメタ文字を利用した高度なパターンマッチング手法
ファイル作成
cat << 'EOF' > input.txt
apple 123
banana 456
cherry abc
date 789xyz
EOF
実行コマンド
awk 'match($0, /[a-z]+ [0-9]+/) { print "MATCH:", $0 }' input.txt
実行結果
MATCH: apple 123
MATCH: banana 456
MATCH: date 789xyz
実行コマンド
awk 'match($0, /[0-9]+$/) { print "END NUMBER:", $0 }' input.txt
実行結果
END NUMBER: apple 123
END NUMBER: banana 456
実行コマンド
awk 'match($0, /^[a-z]+ [0-9]+$/) { print "STRICT MATCH:", $0 }' input.txt
実行結果
STRICT MATCH: apple 123
STRICT MATCH: banana 456
仕組み
| 要素 | 説明 |
|---|---|
| match() | 文字列が正規表現に一致するか判定する関数 |
| [a-z]+ | 小文字アルファベットが1回以上続く |
| [0-9]+ | 数字が1回以上続く |
| ^ | 行の先頭を示す |
| $ | 行の末尾を示す |
| $0 | 行全体を表すawkの変数 |
| /pattern/ | 正規表現リテラル |
解説
match()を使うことで、行単位で高度な正規表現マッチングが可能になります。
アンカー(^, $)や量指定子(+)を組み合わせることで、厳密な条件指定ができます。
match関数をループ処理(while)で活用する方法
ファイル作成
cat << 'EOF' > input.txt
abc123def456ghi789
EOF
実行コマンド
awk '{
while (match($0, /[0-9]+/)) {
print substr($0, RSTART, RLENGTH)
$0 = substr($0, RSTART + RLENGTH)
}
}' input.txt
実行結果
123
456
789
仕組み
| 要素 | 内容 |
|---|---|
| match関数 | 正規表現に一致した位置を返す |
| RSTART | 一致開始位置 |
| RLENGTH | 一致した長さ |
| substr | 一致部分の抽出 |
| whileループ | 一致がなくなるまで繰り返し |
| $0の更新 | 次の検索のため文字列を切り詰め |
解説
matchで数値部分を検出し、whileで繰り返すことで全て抽出しています。
$0を書き換えることで、前回の一致以降を対象にしているのがポイントです。
ログファイルから特定のタイムスタンプやIDのみを抜き出す
ファイル作成
cat << 'EOF' > input.txt
2026-04-29 10:15:23 ID:1001 INFO Login success
2026-04-29 10:16:10 ID:1002 ERROR Failed attempt
2026-04-29 10:17:45 ID:1003 INFO Logout
2026-04-29 10:18:00 ID:1002 INFO Login success
EOF
実行コマンド
awk 'match($0, /ID:1002/)' input.txt
実行結果
2026-04-29 10:16:10 ID:1002 ERROR Failed attempt
2026-04-29 10:18:00 ID:1002 INFO Login success
実行コマンド
awk 'match($0, /^2026-04-29 10:17/)' input.txt
実行結果
2026-04-29 10:17:45 ID:1003 INFO Logout
仕組み
| 要素 | 内容 |
|---|---|
| awk | テキストを1行ずつ処理するコマンド |
| match() | 正規表現に一致するか判定 |
| $0 | 行全体を表す |
| /ID:1002/ | 特定IDに一致 |
| /^2026-04-29 10:17/ | 指定時刻で始まる行に一致 |
解説
match()を使うことで、正規表現に一致した行だけを柔軟に抽出できます。
IDやタイムスタンプなど複雑な条件にも対応可能です。
マルチバイト文字(日本語)を扱う際のmatch関数の注意点と設定
ファイル作成
cat << 'EOF' > input.txt
こんにちは123
abc日本語456
EOF
実行コマンド
awk '{ if (match($0, /[0-9]+/)) print substr($0, RSTART, RLENGTH) }' input.txt
実行結果
123
456
実行コマンド
export LC_ALL=ja_JP.UTF-8
awk '{ if (match($0, /日本語/)) print substr($0, RSTART, RLENGTH) }' input.txt
実行結果
日本語
仕組み
| 項目 | 内容 |
|---|---|
| match関数 | 正規表現に一致した位置をRSTARTに、長さをRLENGTHに格納 |
| RSTART | マッチ開始位置(1始まり) |
| RLENGTH | マッチした文字数 |
| substr | RSTARTとRLENGTHを使って一致部分を取得 |
| 問題点 | デフォルト環境ではマルチバイト文字を1文字として扱わない場合がある |
| 対策 | LC_ALL=UTF-8 などロケールをUTF-8に設定 |
解説
awkのmatchはロケールに依存するため、日本語を扱う場合はUTF-8環境を明示する必要があります。
設定しないと文字位置や長さが正しく取得できないことがあります。
大量のデータを処理する際のmatchの処理速度向上策
ファイル作成
seq -f "%.0f" 5000000 | sed 's/^/apple_/' > input.txt
実行コマンド
time awk '{ if (match($0, /apple_[0-9]+/)) print }' input.txt
実行結果
real 0m17.488s
user 0m8.886s
sys 0m3.553s
実行コマンド
time awk 'BEGIN { pattern = "apple_[0-9]+" } { if ($0 ~ pattern) print }' input.txt
実行結果
real 0m16.747s
user 0m8.320s
sys 0m3.529s
実行コマンド
time awk '{ if (index($0, "apple_")) print }' input.txt
実行結果
real 0m16.200s
user 0m7.591s
sys 0m3.467s
仕組み
| 手法 | 内容 | 速度 | 特徴 |
|---|---|---|---|
| match関数 | 毎回正規表現を評価 | 遅い | 柔軟だがコスト高 |
| 正規表現変数化 | パターンを事前定義して再利用 | 中 | コンパイル回数削減 |
| index関数 | 文字列検索のみ | 速い | 単純一致に最適 |
解説
大量データでは正規表現の再評価コストが支配的になるため、変数化や単純関数への置き換えが有効です。
特に条件が単純ならindexが最速です。
「マッチしない場合」の戻り値のハンドリング
ファイル作成
cat << 'EOF' > input.txt
apple 100
banana 200
cherry 300
EOF
実行コマンド
awk '{ result = match($0, /orange/); print result }' input.txt
実行結果
0
0
0
実行コマンド
awk '{ result = match($0, /apple/); print result }' input.txt
実行結果
1
0
0
仕組み
| 条件 | match関数の戻り値 | 意味 |
|---|---|---|
| マッチする | 1以上の数値 | マッチした開始位置 |
| マッチしない | 0 | 一致しなかった |
| resultに格納 | 数値 | 条件分岐に利用可能 |
解説
matchは一致しない場合に0を返すため、その値で分岐処理を書くことで安全にハンドリングできます。
awkとmatchを使いこなすためのまとめ
awkにおけるmatchの理解は、単なる正規表現の知識ではなく「処理の流れ」を掴むことが重要です。
細かな仕様を理解することで一気に応用範囲が広がります。
今回紹介したポイントを押さえることで、初学者の段階から実務レベルのテキスト処理に近づくことができます。

![[sed] 実行して理解 指定した範囲の行を削除 文字列のsed](https://running-terminal-commands.com/wp-content/uploads/thumbnail_sed_1920_1080.png)