awk
でのパターンはルールの実行を制御している。ルールは現在の入力レコー
ドがその(ルールの持つ)パターンにマッチしたときに実行される。この章では、パ
ターンの書き方について述べる。
ここでは、awk
がサポートしているパターンについて述べる。
/regular expression/
expression
pat1, pat2
BEGIN
END
BEGIN
とEND
を参照.)
null
正規表現は文字列のクラスを記述する手段である。正規表現はスラッシュ
(`/')に囲まれていて属するクラスが、入力レコードと比較されるawk
のパターンである。
最も単純な正規表現は文字、数字の並びである。そのような正規表現はその文字の並
びそのものにマッチする。例えば`foo'という正規表現は`foo'という部分
がある文字列にマッチする。従って、/foo/
というパターンは`foo'とい
う部分がある入力レコードにマッチする。ほかの正規表現は、文字列のより複雑なク
ラスを特定する。
正規表現はスラッシュに囲まれたパターンとして使う事ができる。さらに正規表現は 各レコードのテキスト全体とマッチする (通常は、マッチするテキストの一部分だけ が必要である)。例えば次の例は、レコードのどこでもいいから`foo'という並 びがあればそのレコードの二番目のフィールドを出力する。
awk '/foo/ { print $2 }' BBS-list
正規表現は比較式の中で使う事ができる。文字列をマッチするかどうかテストするこ
とができるが、そのとき入力レコード全体が必要というわけではない。そのような比
較式はパターンとして、あるいは if
文, while
文, for
文,
do
文で使う事ができる。
exp ~ /regexp/
awk '$1 ~ /J/' inventory-shippedこの動作は次のものと同じである。
awk '{ if ($1 ~ /J/) print }' inventory-shipped
exp !~ /regexp/
awk '$1 !~ /J/' inventory-shipped
`~' 演算子や `!~' 演算子の右辺には固定正規表現(例え ばスラッシュの間にあるキャラクタの並び)が必須というわけではなく、 なんらかの式であってもよい。そういった式は評価されて、 必要があれば文字列に変換される。その結果の文字列は正規表現として扱わ れる。このように計算された正規表現は動的正規表現と呼ばれる。例を挙げよ う。
identifier_regexp = "[A-Za-z_][A-Za-z_0-9]+" $0 ~ identifier_regexp
identifier_regexp
にawk
の変数名を表すような正規表現をセットし、
入力レコードに対してこの正規表現がマッチするかどうかテストを行う。
以下に挙げる正規表現演算子、あるいはメタキャラクタと呼ばれるキャ ラクタを使って、正規表現を繋げることができ、それによって正規表現の記述力を向 上させ、融通性を増す。
以下はメタキャラクタの一覧である。ここに挙げられていないキャラクタはそれ自身 を表現するキャラクタである。
^
^@chapterこれは文字列の先頭にある`@chapter'とマッチする。 (Texinfoのソースファイル中の章の始まりの印としてよく使われる)
$
p$これは`p'で終わるレコードにマッチする。
.
.Pこれは文字列中で、`P'が続くキャラクタにマッチする。連結を使うことにより、 間に任意のキャラクタを挟む`U'で始まり`A'で終わる文字の並びにマッチ する`U.A'の様な正規表現を作ることができる。
[...]
[MVX]これは文字列中の`M', `V', `X'のいずれかとマッチする。 キャラクタの範囲は、範囲の始まりと終わりの間にあるハイフンを用いて示される。 これはブラケットの中になければならない。例を挙げると、
[0-9]これは数字のどれかとマッチする。 キャラクタセットの中で、`\', `]', `-', `^'はその前に `\'を置く。例を挙げよう。
[d\]]これは`d'か `]'とマッチする。 この`\'の意味は他の
awk
処理系と同じであり、
POSIX のコマンド言語、標準ユーティリティとも一致する。 awk
での正規表
現はPOSIX の規定した拡張正規表現(EREs)のスーパーセットである。 POSIX EREsは
伝統的なegrep
ユーティリティで使用できる正規表現がベースになっている。
egrep
のシンタクスでは、バックスラッシュはブラケットに囲まれた中では文
法的に特別なものではない。このことは、キャラクタセットのメンバとして
`]', `-', `^'といったキャラクタを使うときには、特殊なトリック
を使わなければならないということを意味している。
egrep
のシンタクスでは、`-'を範囲指定のキャラクタではなく、単なる
`-'にマッチさせる為には`---'と書かなければならない。あるいは
`-'をキャラクタセットの先頭か末尾に置いてもよい。 `^'にマッチさせ
る為には、それをキャラクタセットの先頭以外に置かなければならない。 `]'
にマッチさせる為にはキャラクタセットの先頭にそれを置かなければならない。例を
挙げよう。
[]d^]これは`]'か `d' か `^'にマッチする。
[^ ...]
[^0-9]これは数字以外のキャラクタにマッチする。
|
^P|[0-9]これは`^P'か`[0-9]'のどちらかにマッチする文字列にマッチする。言い 換えるとこのパターンは、`P'で始まるか数字が含まれている文字列にマッチす る。 この選択は演算子の左右のそれぞれで可能な限り大きな正規表現に適用される。
(...)
*
ph*ここで`*'はその前にある`h'に適用され、一文字の`p'に続いて任意 の数の`h'がある文字列にマッチする。これは`p'だけで`h'が一個も ないようなパターンにもマッチする。 `*'のくり返しは、可能なかぎり最も小さな式が採用される。 (もしより大きな 式を繰り返したいのならば括弧を使えばよい) そしてその式は可能な限り大きなくり 返しを見つけだす。例えば、
awk '/\(c[ad][ad]*r x\)/ { print }' sampleこれは入力レコードの中で `(car x)', `(cdr x)', `(cadr x)'など の文字列があるレコードを全て出力する。
+
wh+yこれは`wh*y'にマッチするすべての文字列の中で `why' や `whhy' にはマッチするが、`wy'にはマッチしない。この演算子を使って、先程の `*' を使った例を単純に書き直せる。
awk '/\(c[ad]+r x\)/ { print }' sample
?
fe?dこれは`fed' や `fd'にはマッチするがそれ以外にはマッチしない。
\
\$これは`$'というキャラクタにマッチする。 文字列定数 (セクション 定数式を参照) で使われたエスケープシー ケンスは正規表現として正当であり、それらは`\'が前に置かれる。
正規表現中では`*', `+', `?'といった演算子は最も高い優先順位を 持ち、続いて連結、最後が`|'である。算術式と同じ様に、括弧は 演算子同士の結びつきをどのようにするのかを変更できる。
大小文字は通常正規表現の中では通常のキャラクタマッチのとき(メタキャラクタを除 く)でも、キャラクタセットの内側のときでも区別される。したがって、正規表現中 の`w'は小文字の`w'とだけマッチして大文字の`W'とはマッチしない。
大小文字を無視してマッチを行う最も単純な方法はキャラクタセットを使って `[Ww]'の様にすることである。しかし、これは正規表現を読みにくいものとし てしまう。他に取るべき手段としては二つある。
プログラム中の任意の点で大小文字に関係なくマッチングを行うための手段の一つは、
データをtolower
か toupper
という組み込みの文字列処理関数(まだ
これらの関数の説明はされていない)を使用して、大文字、小文字どちらかに揃えて
しまうというものである。(tolower
及びtoupper
の詳しい説明は、
セクション 組込みの文字列操作関数を参照).
たとえば
tolower($1) ~ /foo/ { ... }
この例ではマッチングを行なう前に、最初のフィールドを小文字に変換している。
別の手段として、変数IGNORECASE
にゼロでない値をセットする。というもの
がある。IGNORECASE
がゼロでないとき、全ての正規表現演算は大小文字を無
視する。 IGNORECASE
の値を変更すると、あなたの書いたプログラムの大小文
字の扱い方を実行時に動的にコントロールできる。デフォルトでは
IGNORECASE
は(他のほとんどの変数と同じように) ゼロに初期化されているの
で、大小文字は区別される。
x = "aB" if (x ~ /ab/) ... # これは失敗する IGNORECASE = 1 if (x ~ /ab/) ... # これは成功する
通常は、IGNORECASE
を使ってあるルールでは大小文字を無視するようにし、
別のルールでは大小文字を区別するようにするということはできない。なぜなら、
IGNORECASE
を特定のパターンのためにセットすることができないからである。
このような動作を行なうためには、キャラクタセットかtolower
を使わなけれ
ばならない。しかし、全てのルールにおいて、大小文字の区別をする、しないを動的
に変更するというのであれば、そのためにIGNORECASE
のオン・オフを切り替
えて行なうことはできる。
IGNORECASE
をコマンドラインやBEGIN
ルール中でセットすることがで
きる。 IGNORECASE
をコマンドラインでセットすることによってプログラムを
修正することなしに、そのプログラムを大小文字を無視するように動作させることが
できる。
gawk
が互換モードで動作している場合、IGNORECASE
の値は
効果を持たない(セクション awk
の起動を参照).
互換モードでは、大小文字は常に区別される。
比較パターンは二つの文字列あるいは数値の間の、等しさのような 関係をテストする。これは式パターンの特殊なケースである (セクション パターンとしての式を参照)。 比較パターンはCのスーパーセットとなっている関係演算子を使って 記述される。関係演算子は次に挙げるものがある。
x < y
x <= y
x > y
x >= y
x == y
x != y
x ~ y
x !~ y
関係演算子のオペランドはその両方ともが数値であれば、数値として比較が行なわれ
る。そうでない場合には (文字列に)変換されてから文字列として比較が行なわれる
(セクション 文字列と数値の変換を参照).
文字列は初めに最初のキャラクタ同士を比較し、次に二番目のキャラクタを、
というように違いがあるまで比較を続ける。
したがって、"10"
は "9"
よりも小さいということになる。
もし、短い文字列が終了するまでが等しい(長さの違う)二つの文字列があった
場合、短い方の文字列は長い方の文字列よりも小さい。とみなされる。したがって
"abc"
は "abcd"
よりも小さい、ということになる。
演算子`~' と `!~'の左に位置するオペランドは、文字列である。右に位
置するオペランドはスラッシュでくくられた (/regexp/
のような)正規
表現か、動的正規表現のように文字列としての値をもつなんらかの式である
(セクション 正規表現の使い方を参照).
以下に挙げる例は入力レコードの中から、第一フィールドが `foo'であるレコードの第二フィールドを出力する。
awk '$1 == "foo" { print $2 }' BBS-list
次に挙げる例では正規表現のマッチングを使って、第一フィールドに `foo'が 含まれるレコードの第二フィールドを出力する。
awk '$1 ~ "foo" { print $2 }' BBS-list
これはまた、次のようにも記述できる。
awk '$1 ~ /foo/ { print $2 }' BBS-list
論理式は異なったパターンを "or" (`||'), "and"(`&&'), "not" (`!') のような論理演算子を使って繋げた式である。入力レコー ドに対する論理式全体のパターンマッチは、各部分の式のマッチングの結果による。
例えば次のコマンドは入力ファイル`BBS-list'中のレコードのうち、 `2400' と `foo'の両方を含むものを出力する。
awk '/2400/ && /foo/' BBS-list
次のコマンドは入力ファイル`BBS-list'中のレコードのうち、`2400' と `foo'のどちらか、あるいは両方を含むものを出力する。
awk '/2400/ || /foo/' BBS-list
`BBS-list'中のレコードのうち、`foo'を 含まないものを出力す る。
awk '! /foo/' BBS-list
論理パターンは式パターンの特殊なケースであり、 (セクション パターンとしての式を参照) 論理演算子を使った式である。 セクション 論理式を参照.に論理演算子の詳しい 記述がある。
論理パターンの部分式は固定正規表現や、比較式、あるいはほかの awk
の
式であってもかまわない。範囲パターンは式ではないので論理パターンに含めること
はできない。同様に、特殊パターンのBEGIN
と END
もまた、入力レコ
ードのいずれともマッチせず、式や論理パターンの中に記述することはできない。
awk
では、式はawk
のパターンとしての値を持っている。式の値が0以
外(数値の場合)か、空文字列(文字列の場合)でない場合パターンがマッチしたこ
とになる。
式は新しく入力レコードに対してルールが検査されるごとに再評価される。もし式が
$1
のようなフィールドを使っていたならばその値は新たな入力レコードのテ
キストによって決定する。そうでない場合、式はawk
プログラムの実行とは関
係ないところに依存する形となるが、それでも便利であろう。
パターンの比較はこのような場合の特殊な形である。たとえば、$5 == "foo"
という式は $5
の値が "foo"
と等しいときに1という値を持ち、等し
くなければ0という値を持つ。したがって、この式は二つの値が等しいときにパターン
がマッチしたということになる。
論理式は式の特殊なケースである。
パターンとしての正規表現もまた式の特殊なケースである。 /foo/
はカレン
ト入力レコード中に`foo'があれば 1という値を持つ式である。したがって、
/foo/
は `foo'を含むレコードにマッチするパターンである。
他のawk
処理系ははgawk
ほどにはPOSIXに準拠していない。
具体的には、比較式や論理式は許されるが、そのほかの種類の式は使えない。
範囲パターンはbegpat, endpat
のように、カンマで区切
られた二つのパターンからなる。これは連続した範囲の入力レコードにマッチする。
最初のパターンbegpatは範囲の始まりを制御し、二番目のパターン
endpatは範囲の終わりを制御する。たとえば、
awk '$1 == "on", $1 == "off"'
これは`on'/`off'のあるレコードの間にあるレコードを `on'/`off'のあるレコードも含めて出力する。
範囲パターンは入力レコードと比較しbegpatとマッチすることで始まる。レコ ードがbegpatとマッチした時、範囲パターンは真となる。 endpatとマッ チする入力レコードがみつかるまですべての入力レコードはパターンにマッチしたと 扱われる。 endpatとマッチする入力レコードが見付かったとき、範囲パター ンはそれ以降の入力レコードのマッチングの際には偽となる。そして今度はまた入力 レコードとbegpatがマッチするかどうかを検査するのである。
範囲パターンを真にしたり、偽にしたりしたレコードそのものも範囲パターンにマッ
チしたと扱われる。もしここでそのようなレコードは扱いたくないというのであれば
if
文を使って、ルールのアクション部分でそのようなレコードを区別すれば
良い。
範囲の始まりと終わりを同じパターンにすることも可能である。そのような場合、ア クションはマッチしたレコードに対してのみ実行される。
BEGIN
とEND
BEGIN
とEND
は特殊なパターンである。これらのパターンは入力レコー
ドとのマッチングには使用されず、 awk
スクリプトのスタートアップやクリー
ンアップに使われる。 BEGIN
ルールは一度だけ、最初の入力レコードが読み
込まれる前に実行され、END
もやはり一度だけ、すべての入力が行なわれた後
で実行される。例を挙げよう。
awk 'BEGIN { print "Analysis of `foo'" } /foo/ { ++foobar } END { print "`foo' appears " foobar " times." }' BBS-list
このプログラムは入力ファイル`BBS-list'中のレコードのうち、 `foo'と
いう文字列を含むレコードの数を出力する。 BEGIN
ルールでレポートのタイ
トルを出力する。ここで、BEGIN
ルールの中で、カウンタに使用する変数
foobar
を 0に初期化する必要はない。awk
が自動的にそれを行なうか
らである (セクション 変数を参照).
二番目のルールで、`foo'を含むレコードを読むたびに変数foobar
をイ
ンクリメントしている。 END
ルールでは実行終了時のfoobar
の値を出
力している。
BEGIN
と END
は範囲を示すためには使えないし、論理演算子と一緒に
使うこともできない(それどころかそれらは他の演算子と一緒に使うこともできない)。
awk
プログラムではBEGIN
ルールや END
ルールを複数記述する
こともできる。そのような複数のルールは、プログラムの先頭から見付かった順に全
てのBEGIN
ルールはスタートアップ時に、全てのEND
ルールは終了時に
実行される。
複数のBEGIN
や END
はライブラリを記述するのに便利である。ライブ
ラリはそれぞれ自分のBEGIN
ルールや END
ルールを自分のスタートアッ
プやクリーンアップのために持つことができる。気を付けなければならないのは、コ
マンドラインに記述されるライブラリの名前の順番によって、(ライブラリ中の)
BEGIN
ルールや END
ルールの実行される順番が左右されるということ
である。したがって、ライブラリファイルで実行される順番に依存するような記述を
しないように注意しなければならない。より詳しいライブラリ関数の使い方は
セクション awk
の起動を参照,を参照のこと
awk
プログラムがBEGIN
ルールだけで他のルールを持っていない場合、
BEGIN
ルールの実行をした後でプログラムを終了する(古いバージョンの
awk
では入力を続け、ファイルの終端にくるまで入力を無視し続ける)。しか
し、同様にEND
ルールだけがプログラム中にあった場合、入力は行なわれる。
これは END
ルールでNR
変数をチェックするようなケースに必要である
からである。
BEGIN
ルールおよび、 END
ルールはアクション部を持っていなければ
ならない。これらのルールにはデフォルトアクションはなく、実行時にカレントレコ
ードも存在しないからである。
空のパターンは全ての入力レコードにマッチするとみなされる。 たとえば次のプログラムは
awk '{ print $1 }' BBS-list
全てのレコードの第一フィールドを出力する。