移動先 先頭, 前, 次, 末尾 セクション, 目次.

パターンとアクション

既に説明したように、それぞれのawkの文は アクションを伴ったパターンから構成されている。 この章ではパターンとアクションをどのように作成するかを 説明する。

Pattern Elements

awkのパターンはルールの実行を制御する。あるルールはそのパターンと カレント入力レコードがマッチしたときに実行される。このセクションではパタ ーンの記述の仕方を説明する。

パターンの種類

以下にawkでサポートしているパターンをまとめる。

/regular expression/
正規表現はパターンのようなものであり、入力レコードのテキストに一致したとき マッチする。 (セクション 正規表現を参照.)
expression
一つの式。数値に変換して0でない、もしくは空でない文字列のときに マッチする (セクション パターンとしての式を参照.) カンマで区切られた二つのパターンはレコードの範囲を指定する。 この範囲にはpat1にマッチした 最初のレコードと、pat2にマッチした最後のレコードの両方が 含まれる(セクション パターンを使ったレコード範囲の指定を参照.)。
BEGIN
END
awkプログラムで、前処理もしくは後処理をするための特別なパターン (セクション 特殊パターンBEGINとENDを参照.)
empty
空のパターンはすべての入力レコードにマッチする (セクション 空パターンを参照.)。

パターンとしての正規表現

これまでのサンプルの中で、正規表現をパターンとして使ってきた。 この種類のパターンは、 あるルールのパターン部分にある 単純な正規表現定数である。それは`$0 ~ /pattern/'. と同じ意味を持つ。これは入力レコードが正規表現にマッチしたとき、 (入力レコードに)マッチするパターンである。 例を挙げよう。

/foo|bar|baz/  { buzzwords++ }
END            { print buzzwords, "buzzwords seen" }

パターンとしての式

awkの任意の式は、そのままawkの正しいawkのパターンである。 そして、式の値が非0(数値の場合)でもなく、空でない文字列 (文字列の場合)の場合には、パターンマッチするということになる。

式は、ルールが新たな入力レコードに対してテストされる度に再評価が 行われる。もしここで式が$1のようなフィールドを使っていた のならば、その値は新たな入力レコードテキストによるものである。 それ以外のものはawkプログラムの実行時の動作にのみ 依存する。

パターンとして使われている式は、一般的に セクション Variable Typing and Comparison Expressionsを参照. にある比較演算子を使った比較式をパターンとして使っている。

(セクション 動的正規表現を使うを参照). 正規表現マッチング(と非マッチング)は非常に一般的な式である。 `~'演算子や`!~'演算子の左オペランドは 文字列であり、右オペランドはスラッシュで囲まれた (/regexp/のような)正規表現定数か 動的正規表現として扱われる文字列値を持つ任意の式である。

`~'演算子や`!~'演算子の左オペランドは文字列であり、 右オペランドは(/regexp/)のように スラッシュで囲まれた正規表現定数か、動的正規表現として使用される 文字列としての値を持つ任意の式である (セクション 動的正規表現を使うを参照)。

次に挙げる例は、第一フィールドが`foo'である入力レコードの第二フィ ールドを出力する。

$ awk '$1 == "foo" { print $2 }' BBS-list

(これはなにも出力しない。なぜなら、"foo"という名前のBBSは ないからだ。) 対照的に、次の例では 第一フィールドに`foo'を含むレコードを出力するものである。

$ awk '$1 ~ /foo/ { print $2 }' BBS-list
-| 555-1234
-| 555-6699
-| 555-6480
-| 555-2127

ブール式もまた同様にパターンとして使われている。パターンが入力レ コードにマッチするかどうかを、部分式がマッチするかどうかで判定す る。

例を挙げると、次のコマンドは `2400'と`foo'の両方を含む`BBS-list'中の レコード全てを出力する。

$ awk '/2400/ && /foo/' BBS-list
-| fooey        555-1234     2400/1200/300     B

次の例は`2400' か `foo'のいずれか(両方でもよい)を含む `BBS-list'中のすべてのレコードをすべて出力する。

$ awk '/2400/ || /foo/' BBS-list
-| alpo-net     555-3412     2400/1200/300     A
-| bites        555-1675     2400/1200/300     A
-| fooey        555-1234     2400/1200/300     B
-| foot         555-6699     1200/300          B
-| macfoo       555-6480     1200/300          A
-| sdace        555-3430     2400/1200/300     A
-| sabafoo      555-2127     1200/300          C

次の例では、`foo'という文字列を含まない`BBS-list'の レコードを全て出力する。

$ awk '! /foo/' BBS-list
-| aardvark     555-5553     1200/300          B
-| alpo-net     555-3412     2400/1200/300     A
-| barfly       555-7685     1200/300          A
-| bites        555-1675     2400/1200/300     A
-| camelot      555-0542     300               C
-| core         555-2912     1200/300          C
-| sdace        555-3430     2400/1200/300     A

パターン中にあるブール演算子の部分式は、正規表現定数や、比較、あるいは任 意のawk式であってよい。範囲パターンは式ではなく、論理パターンの内 側に置くことはできない。同様に、あらゆる入力レコードとはマッチしないスペ シャルパターンBEGINやENDも式ではなく、論理パターンの内側に 置くことはできない。

パターンとしての正規表現定数も同様に expression patternの特殊な ケースである。/foo/は、 `foo'がカレント入力レコードにあるときに1という値を持つ式である。 したがって、/foo/は`foo/'を含むレコードにマッチする パターンである。

パターンを使ったレコード範囲の指定

範囲パターン(range pattern)はbegpat, endpatの ように、カンマで区切られた二つのパターンからなる。これは連続した範囲の 入力レコードにマッチする。最初のパターンbegpatは範囲の始まりを制 御し、二番目のパターンendpatは範囲の終わりを制御する。たとえば

awk '$1 == "on", $1 == "off"'

これは`on'/`off'のあるレコードの間にあるレコードを `on'/`off'のあるレコードも含めて出力する。

範囲パターンは入力レコードと比較しbegpatとマッチすることで始まる。レコ ードがbegpatとマッチした時、範囲パターンは真となる。 endpatとマッ チする入力レコードがみつかるまですべての入力レコードはパターンにマッチしたと 扱われる。 endpatとマッチする入力レコードが見付かったとき、範囲パター ンはそれ以降の入力レコードのマッチングの際には偽となる。そして今度はまた入力 レコードとbegpatがマッチするかどうかを検査するのである。

範囲パターンを真にしたり、偽にしたりしたレコードそのものも範囲パターンにマッ チしたと扱われる。もしここでそのようなレコードは扱いたくないというのであれば if文を使って、ルールのアクション部分でそのようなレコードを区別すれば 良い。

範囲の始まりと終わりを同じパターンにすることも可能である。そのような場合、ア クションはマッチしたレコードに対してのみ実行される。

例えば、二つの目印(ここでは`%'としよう)に挟まれている テキストを無視したいと考えたとしよう。 これを区切りのテキストを記述した範囲パターンとnext文 (まだ説明していない。セクション The next Statementを参照) を組み合わせて、awkに処理をスキップさせることを 例えば以下ののプログラムのようにして試みるかもしれない。

/^%$/,/^%$/    { next }
               { print }

このプログラムは、`%'だけがある最初の行で 範囲の開始と終了を行ってしまうので失敗してしまう。 これを行うには、フラグを使用して次のようなプログラムを 書かなければならない。

/^%$/     { skip = ! skip; next }
skip == 1 { next } # `skip' がセットされていたらその行を飛ばす

範囲パターンの中では、`,'はすべての演算子の中で もっとも優先順位の低い(最後に評価が行われる)演算子であることに 注意すること。したがって、次の例のようなプログラムでは 別の単純なテストと範囲パターンが組み合わされて扱われてしまう。

echo Yes | awk '/1/,/2/ || /Yes/'

このプログラムの作者は`(/1/,/2/) || /Yes/'のつもりだった。 しかし、awkはこれを`/1/, (/2/ || /Yes/)'のように 解釈する。これは変更したり、対処したりすることはできない。 範囲パターンは他のパターンと組み合わせないこと。

特殊パターンBEGINとEND

BEGINとENDは特殊なパターンである。 これらは入力レコードにマッチするためには使われなず、 awkスクリプトのスタートアップやクリーンアップに 使われる。

Startup and Cleanup Actions

BEGINルールは一度だけ、最初の入力レコードが読み込まれる前に実行され、 ENDもやはり一度だけ、すべての入力が行なわれた後で実行される。 例を挙げよう。

$ awk '
> BEGIN { print "Analysis of \"foo\"" }
> /foo/ { ++n }
> END   { print "\"foo\" appears " n " times." }' BBS-list
-| Analysis of "foo"
-| "foo" appears 4 times.

このプログラムは入力ファイル`BBS-list'中のレコードのうち、 `foo'と いう文字列を含むレコードの数を出力する。 BEGINルールでレポートのタイ トルを出力する。ここで、BEGINルールの中で、カウンタに使用する変数 foobarを 0に初期化する必要はない。awkが自動的にそれを行なうか らである (セクション Variablesを参照).

二番目のルールで、`foo'を含むレコードを読むたびに変数foobarをイ ンクリメントしている。 ENDルールでは実行終了時のfoobarの値を出 力している。

BEGIN と ENDは範囲を示すためには使えないし、論理演算子と一緒に 使うこともできない(それどころかそれらは他の演算子と一緒に使うこともできない)。

awkプログラムではBEGIN ルールや ENDルールを複数記述 することもできる。そのような複数のルールは、プログラムの先頭から見付かっ た順に全てのBEGINルールはスタートアップ時に、全てのENDルー ルは終了時に実行される。この機能は、awkの1987年のバージョンで付け 加えられた。また、これはPOSIXの標準にも含まれている。オリジナル(1978年) のawkでは、BEGINルールはプログラムの先頭に、ENDルー ルはプログラムの最後に置かれていて、それぞれプログラム中に一つだけあるこ とを要求していた。今やこうする必要はないのだが、このようにすることはプロ グラムの構成を改良し、可読性を向上させるアイデアではある。

複数のBEGIN や ENDはライブラリを記述するのに便利である。ラ イブラリはそれぞれ自分のBEGIN ルールや ENDルールを自分のス タートアップやクリーンアップのために持つことができる。気を付けなければな らないのは、コマンドラインに記述されるライブラリの名前の順番によって、 (ライブラリ中の)BEGIN ルールや ENDルールの実行される順番 が左右されるということである。したがって、ライブラリファイルで実行される 順番に依存するような記述をしないように注意しなければならない。より詳しい ライブラリ関数の使い方は セクション コマンドラインオプションを参照、 便利なライブラリ関数は セクション awkの関数ライブラリを参照。

BEGINルールだけで、他のルールを一切持っていないawkプログラ ムは、BEGINルールを実行した後でプログラムの実行を終了する(オリジ ナルバージョンのawkでは、ファイルの終端まで入力ファイルを読み込み、 呼んだ内容を無視していた)。しかし、ENDルールがあった場合には他の ルールがなかったとしても、入力の読み込みを行う。これはENDルールで FNR や NRという変数をチェックする場合に必要だからである (d.c.)。

BEGIN ルールおよび、 ENDルールはアクション部を持っていなければ ならない。これらのルールにはデフォルトアクションはなく、実行時にカレントレコ ードも存在しないからである。

Input/Output from BEGIN and END Rules

BEGINルールやENDルールから入出力を行ったときに 生じる幾つかの(時として微妙な)事柄がある。

第一の点は、BEGINルール中で$0の値を扱うことに関してのもの である。BEGINルールは何等かの入力が行われる前に実行されるので、入 力レコードも、フィールドもBEGINルール実行時には存在していない。 $0やフィールドを参照すると、その結果は空文字列かゼロ(これは文脈によ る)のいずれかになる。$0に本当の値を格納する手段としては、変数指定 なしでgetline(セクション getlineを使った入力を参照) コマンドを使うというものがある。もう一つのやり方として、単に値を代入すると いう手段もある。

第二の点は第一のものに似ているが、違う方向のものである。ENDルール の内側では、$0やNFは伝統的に大部分の処理系においてEND ルール中の$0やNFは未定義だった。POSIXの標準は、 NFがENDルール中で使用可能であることを規定しており、その内容 は最後の入力レコードのフィールド数を保持しているように定められている。恐 らくは見落としのために、この標準では論理上そう考えるべきであるにもかから わず、$0を同様に保存するということに言及していない。事実、 gawkはENDルールのために、$0の値を保存している。

第三の点は、先の二つに関連するものである。BEGINルールや ENDルール中で`print'が意味するところはなんだろうか? それは通常と同じく、`print $0'である。 $0が空文字列であれば、空行が印刷される。 長い間awkプログラマは、BEGINルールやENDルールの 中で、$0が空文字列であることを当てにして `print ""'の意味で`print'を使っていた。 BEGINルールでこれを使っていたらそれはやめたほうが良い。 少なくともgawkを使っているときには、これを ENDルールで使うのは悪いアイデアである。 これは良くないスタイルであり、空の行を出力したいのならば それを明確に記述すべきである。

空パターン

空のパターン(つまり、パターンがないということ)はすべての入力レコー ドとマッチするように扱われる。例えば次のプログラムでは、

awk '{ print $1 }' BBS-list

すべてのレコードの第一フィールドを出力する。

Overview of Actions

awkのプログラムはルールと関数定義などの並びの集まりである (関数はこの後で説明する。 セクション ユーザー定義関数を参照.)。

ルールはパターンとアクション、もしくはそのどちらか一方からなる。 アクションの目的はawkに対してパターンがマッチしたときに何を行な うかを示すということである。したがって、完全な形のプログラムは次のようなもの である。

[pattern] [{ action }]
[pattern] [{ action }]
...
function name(args) { ... }
...

アクションは、カーリーブレース(`{' and `}')に囲まれたひとつ以上 のawkの文から構成される。それぞれの文は一つのことをする。文は改行かセ ミコロンで区切られている。

たとえアクション部がたった一つの文だけであったり、文がなかったとしても、アク ション部をカーリーブレースで囲まなければならない。しかし、アクション部を省略 するのであればカーリーブレースも一緒に省略することができる(省略されたアクショ ンは`{ print $0 }'と同じ働きをする)。

/foo/  { }  # fooにマッチして、なにもしない - 空のアクション
/foo/       # fooにマッチしてレコードを出力 - 省略されたアクション

以下に挙げるものはawkがサポートする文の種類である。

次の章は制御文を詳しく説明している。


移動先 先頭, 前, 次, 末尾 セクション, 目次.