awk はテキスト処理のツールなので, テキストの構造を記述する厳密な方法を持っている. これを正規表現と呼ぶ. 正規表現について一定の知識を持っていることが, awk でのテキスト処理に不可欠である.
awk では本処理のパターン{アクション} の, パターンを指定するのに正規表現が, よく使われる.
awk のメタキャラクタを挙げれば, 代表的なものは次のようなものである:
. ピリオドは任意の一文字を表す
* 直前の文字の 0 個以上の繰り返しを表す
[例]
ab*: a の後ろに b が 0 個以上に続く.
ab.*: ab の後ろに任意の文字が 0 個以上続く.
+ 直前の文字の 1 個以上の繰り返し
[例]
ab+: a の後に b が 1 個以上続く.
ab.+: ab の後に任意の文字が 1 個以上続く.
^ 文字列の先頭を表す
[例]
^a: 先頭に a が来ることを表す.
^ab: 先頭に ab が来ることを表す.
$ 文字列の末尾を表す
[例]
a$: 文字列が a で終わることを表す.
ab$: 文字列が ab で終わることを表す.
^$: 空の文字列を表す.
[] [ ] の中の任意の文字を表す
[例]
[abc]: a か b か c か を表す.
[あ-ん]: 全てのひらがな. - で範囲を指定できる.
| 2つの正規表現の選択
[例]
ab|cd: ab か cd かを意味する.
() グループ化する
[例]
(ab|cd|ef) ab か cd か ef か を意味する.
\ 次に来る文字, それ自体を表す. 通常, メタキャラクタの前につけて,
そのメタキャラクタとしての意味を打ち消し, 通常の文字として
扱うことを意味する.
[例]
\. ピリオドそのものを表す.
\\ \ そのものを表す.
awk の本処理は何度も述べてきたように:
パターン{アクション}
という形式を持っている. パターンの部分は, テキストの特性を記述し, 入力行がその特性を持っているなら, {アクション} を実行する.
テキストがあるパターンを持っているかどうかを試すことをパターンマッチングと言う.
たとえば, 入力行の第 1 フィールドが h という文字で始まるというパターンは, 次のようになる:
$1 ~ /^h/{print}
一つの具体的な例を挙げると, 下のようになる:
[cactus:~/code_py/sphinx]% ls -l | gawk '$9 ~ /^h/ {print}'
-rw-r--r-- 1 Wtopia staff 101 Nov 6 16:30 haskell.rst
-rw-r--r-- 1 Wtopia staff 7325 Nov 3 04:15 haskell.rst~
drwxr-xr-x 66 Wtopia staff 2244 Nov 3 04:15 html_tuts/
ここで, 半角の ~ は 左辺の文字列が, 右辺の正規表現に適合することを意味する演算子である.
そして !~ を使うと, 左辺の文字列が, 右辺の正規表現に不適合となる.
正規表現には実際に使ってみよう. scpt7.txt というファイルを用意しておこう:
scpt7.txt
apple egg
hat cat
money sky
absent boy
food note
way arrow
foot cap
value dog
home wall
tree sad
下記のスクリプトは, 入力行の 第 2 フィールドが c という文字で始まるというパターンに適合するときだけ実行される.
FNR はファイルの何行目を読んだいるのかを示す. awk の組み込み変数である.
scpt7_1.awk
#!/usr/local/bin/gawk -f
# scpt7_1.awk
$2 ~ /^c/{
print FNR ":" $2 # 特殊変数 FNR は現在のファイルの入力レコード
}
scpt7_1.awk の実行結果は:
[cactus:~/code_awk/tuts]% ./scpt7_1.awk scpt7.txt
2:cat
7:cap
次は入力行がある文字で終わるかどうかのパターンマッチングの例である.
scpt7_2.awk
#!/usr/local/bin/gawk -f
# scpt7_2.awk
$1 ~ /e$/{ # 第 1 フィールドの単語が e で終わるものを出力
print FNR ":" $1
}
scpt7_2.awk の実行結果は:
[cactus:~/code_awk/tuts]% ./scpt7_2.awk scpt7.txt
1:apple
8:value
9:home
10:tree
次はパターンを否定表現である.
scpt7_3.awk
#!/usr/local/bin/gawk -f
# scpt7_3.awk
$1 !~ /e$/{ # 第 1 フィールドの単語が e で終わらないものを出力
print FNR ":" $1
}
scpt7_3.awk の実行結果は:
[cactus:~/code_awk/tuts]% ./scpt7_3.awk scpt7.txt
2:hat
3:money
4:absent
5:food
6:way
7:foot
パターンで, $0 を調べるときには $0 を省略して, 正規表現だけを書くが許される. 次のスクリプトは, $0 すなわち入力全体が “a” で始まる行を出力する.
scpt7_4.awk
#!/usr/local/bin/gawk -f
# scpt7_4.awk
/^a/{ # $0 ~ /^a/ と同じ意味
print FNR ":" $0
}
scpt7_4.awk の実行結果は:
[cactus:~/code_awk/tuts]% ./scpt7_4.awk scpt7.txt
1:apple egg
4:absent boy
このような正規表現によって, 文字列のパターンを記述し, 実際のテキストがその正規表現に適合するかどうか, すなわち, 正規表現で表されるパターンを持っているかどうかテストすることをパターン・マッチングの例をもう少しあげよう:
/^$/ {print "..."} # 改行だけの空の行を点線に換える
/^[a-zA-Z]+$/ {print} # アルファベットだけの行を出力
/^[a-zA-Z]+/ {print} # アルファベットを 1 文字以上含む行を出力
/^[a-zA-Z \t]+$/ {print} # アルファベットとスペース, タブだけの行を出力
/^[0-9]+$/ {print} # 数字だけの行を出力
/^[0-9\.]+$/ {print} # 数字と小数点だけの行を出力
/^[aA]/ {print} # a か A で始まる行を出力
/^(This|That)/ {print} # This か That という語句で始まる行を出力