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

アクションとしての式

式はawkのアクションの基本的な構成要素である。式を評価して得た値を出力 することもできるし、テストしたり、変数に格納したり関数に渡すこともできる。そ れに加えて、代入文を使うことによって新たな値を変数やフィールドに代入すること もできる。

式は文としても扱われる。大部分の文はオペランドとなるデータを特定する一つ以上 の式からなる。他の多くの言語と同様に、awkにおける式は変数や、配列の参 照、定数、関数呼び出し。そしてそれらの演算子による組み合わせも含まれる。

定数式

もっとも単純な式は定数である。これは常に同じ値を持つ。定数には三種類あ り、数値定数、文字列定数、正規表現定数である。

数値定数は数を意味する。この数は整数でも良いし、小数でも良いし、指数表 示の数であっても良い。 awkではすべての数値は倍精度の浮動小数点数であ る。以下に数値定数の例をいくつか挙げる。これらはすべて同じ値を持つ。

105
1.05e+2
1050e-1

文字列定数とはダブルクォーテーションでくくられた文字の並びである。 例えば、

"parrot"

これは`parrot'という文字列である。 gawkにおける文字列は、NULを含 めて8ビットのASCIIキャラクタの全てを要素として持つことができ、長さも任意であ る。他のawkの実装では一部のキャラクタコードを文字列の要素とすることは 難しいかもしれない。

一部のキャラクタは文字列定数のなかでリテラルとして記述することができない。そ のような場合、バックスラッシュ(`\')で始まる エスケープシーケンス と呼ばれるキャラクタの並びを使うことによって記述することができる。

エスケープシーケンスの使い方のひとつはダブルクォーテーションを文字列定数の中 に記述するというものである。そのままのダブルクォーテーションは文字列の終わり を示すので、 `\"'を使って文字列の一部としてひとつのダブルクォーテーショ ンであるということを示さなければならない。バックスラッシュキャラクタ自身がそ のままでは文字列に含めることのできないキャラクタである。文字列中にバックスラッ シュを含めるには`\\'と記述しなければならない。したがって、二つのキャラ クタ`"\'を文字列に含めるには "\"\\"と記述しなければならない。

バックスラッシュのもうひとつの使い方は、改行のような表示できないキャラクタを 表現するためというものである。これらのキャラクタの大部分は文字列中に直接書く ことができないし、見ることもできない。

以下に挙げるのは awkで使えるエスケープシーケンスのすべてである。

\\
バックスラッシュ、`\'を表わす。
\a
警告キャラクタ、コントロールG、ASCIIコードの7を表わす。
\b
バックスペース、コントロールH、ASCIIコードの8を表わす。
\f
改ページ、コントロールL、ASCIIコードの12を表わす。
\n
改行、コントロールJ、ASCIIコードの10を表わす。
\r
復帰、コントロールM、ASCIIコードの13を表わす。
\t
水平タブ、コントロールI、ASCIIコードの9を表わす。
\v
垂直タブ、コントロールK、ASCIIコードの11を表わす。
\nnn
8進数でnnnを表わす。nnnは0から7までの数字の1つから3つまでの並び である。たとえばASCIIのエスケープキャラクタは `\033'である。
\xhh...
16進数でhhを表わす。hhは16進文字が入る(`0' から `9'と、 `A' から `F'`a' から `f')。 ANSI Cと同様にエスケープ シーケンスは最初に16進数字でないキャラクタが見付かるまで続くが、3つ以上の16 進数字は未定義の値を作り出す (`\x'エスケープシーケンスは POSIX の awkでは許されていない)。

固定正規表現/^beginning and end$/のようにスラッシュで囲まれて 記述された正規表現である。 awkプログラム中で記述される正規表現は大部 分が固定的なものであるが、`~'`!~'といった演算子は"動的な"正 規表現や、演算された正規表現にマッチさせることもできる (セクション 正規表現の使い方を参照).

固定正規表現は単純な式のように使われるだろう。固定正規表現が`~' 演算子 や`!~'演算子の右辺にない場合はパターンの中にそれがあるかのように扱われ る。たとえば、`($0 ~ /foo/)' (セクション パターンとしての式を参照).は 二つのコード部分があることを示している。

if ($0 ~ /barfly/ || $0 ~ /camelot/)
    print "found"

if (/barfly/ || /camelot/)
    print "found"

の二つは同じ動作をする。このルールのより奇妙な結果は、次の論理式が正しいも のであるにも関らず、ユーザーが思ったようには動作しないということである。

if (/foo/ ~ $1) print "found foo"

このコードは"明らかに"$1/foo/という正規表現とのマッチング を行なうように見える。しかし実際にはこの(/foo/ ~ $1)という式は (($0 ~ /foo/) ~ $1) と同じである。言い換えるならば、最初に入力レコー ドに対して /foo/という正規表現を適用する。その結果は0か1のどちらかで あり、マッチの成否によって決定される。その結果に対してレコードの第一フィールド を適用してマッチングを行なう。

こういった動作は本当にユーザーが望んでいたテストとは違ったものであろうから、 こういった文をプログラム中で見つけると、gawkは警告を発する。

もうひとつ、このルールによる結果は代入文でも起きる。

matches = /foo/

この例では変数matchesに、カレント入力レコードの内容によって0か1のどち らかが代入される。

固定正規表現は通常、関数subや 関数gsubの第一引数として使われる (セクション 組込みの文字列操作関数を参照).

言語のこの特徴は POSIX 規格まで明確にされなかった。

$1 ~ /foo/ { ... }

これはつぎの例よりも好ましい。

$1 ~ "foo" { ... }

`~'演算子の右辺が、両方とも定数であるので、 `/foo/'を使った方がよ り効率が良い。 awkは正規表現を与えられたときのように、パターンマッチ ングに定数を使用する。二番目の書き方では、awkはまず最初に文字列を内部 表現に変換せねばならず、その後でパターンマッチングが行なわれる。最初の書き方 はより良いスタイルであり、正規表現のマッチングを行なうということが明確にわか る。

変数

変数にはあとでその値を参照するために名前が付けられている。これまでにも多くの 例で変数が出てきた。変数の名前は文字、数字、あるいはアンダースコアの並びでな ければならず、かつ、先頭が数字であってはいけない。変数名の大小文字はくべつさ れ、したがってaAは別の変数である。

変数名はそれ自身が、変数の現在の値を表わす一つの正しい式である。 変数は代入演算子増加演算子によって新たな値を与えられる。 セクション 代入式を参照.

一部の変数はあらかじめ特別な意味を持っているものがある。フィールドセパレータ としてのFSやカレント入力レコード中のフィールド数を表わすNFなど がそれである。 セクション 組込み変数を参照.にそういった変数のリスト がある。これら組み込み変数は他の変数のように代入したり値を参照したりできるが、 その値は自動的にawkが変更したり、使ったりする。組み込み変数の名前はそ れぞれ大文字だけからなる。

awkでの変数は数値でも文字列でも代入することができる。デフォルトでは文 字列は空文字列で初期化され、それが数値に変換されるときには 0として扱われる。 このことは、awkではCやその他の多くの言語のように変数の初期化を陽に 行う必要がないということである。

コマンドラインでの変数への代入

awkを起動したときに、コマンドライン上の引数にvariable assignment を含めることによって、awkの変数に値をセットすることができる。 代入は次のような形式である。

variable=text

こうすることによって、変数に対する値の設定をawkの起動時か 入力ファイルと入力ファイルの間で行なうことができる。

ここで、代入の前に`-v'というオプションを次のように付けた場合、

-v variable=text

変数に対する値の設定は一番最初、BEGINルールが実行される前に行なわれ る。`-v'オプションとその後の代入はすべてのファイル名の引数の前になけれ ばならず、またプログラムテキストが(コマンドラインで)与えられている場合にも、 それの前になければならない。

そうでない場合には、変数に対する代入は前に位置しているファイル名を示す 引数が処理された後で行なわれる。たとえば、

awk '{ print $n }' n=4 inventory-shipped n=2 BBS-list

この例は全ての入力レコードのフィールド番号がnのフィールドを出力する。 最初のファイルが読まれる前に、コマンドラインで変数nに4がセットされる。 これによって、`inventory-shipped'から入力されるレコードの 4番目のフィー ルドが出力される。最初のファイルの処理が終ったあと、そして二番目のファイルの 処理が始まる前に、nは2にセットされる。したがって、`BBS-list'のレ コードの二番目のフィールドが出力される。

コマンドライン引数はawkプログラム中でARGVという名前の 配列によって参照することができる。(セクション 組込み変数を参照).

awkはコマンドラインでの代入の値をエスケープシーケンスとして 処理する(セクション 定数式を参照).

算術演算子

awk言語は式を評価するときに一般的な算術演算子を使用する。 これら全ての算術演算子は次のような優先順位がある。 次に挙げる例では、第三フィールドの値を第四フィールドの値で割って、 それに第二フィールドの値を足し、結果を第一フィールドに格納する。 そして変更された入力レコードを出力する。

awk '{ $1 = $2 + $3 / $4; print }' inventory-shipped

awkでの算術演算子は以下のものがある。

x + y
加算。
x - y
減算。
- x
符号反転
+ x
単項のプラス。実際には何の効果もない。
x * y
乗算。
x / y
除算。awkでは数値は全て倍精度浮動小数点数として扱われるので 商は整数に丸められない。3 / 4の結果は0.75となる。
x % y
剰余。これは、商は0方向の整数に丸められ、それにyを掛けたも のを xから減算した結果である。この操作は"trunc-mod."とし て知られる。以下の関係が常に保たれる。
b * int(a / b) + (a % b) == a
あるいは望ましくないであろう、この剰余の定義が起こす効果は xが負であっ たときには x % yの結果も負になるということである。
-17 % 8 = -1
他のawk処理系では、剰余の符号はその処理系が動いているマシンに依存する。
x ^ y
x ** y
べき乗。xy乗する。2 ^ 3の値は8である。 `**'という キャラクタの並びは`^'と同じ働きをする。 (POSIXの標準ではべき乗に `^'だけが使える)

文字列の連結

文字列の演算子はただひとつ、連接だけしかない。そして連接は明確にそれを表わす 演算子を持っておらず、その代わりにある式に続いて何の演算子もはさまずに別の 式を書いたときに連接動作が行なわれる。

awk '{ print "Field number one: " $1 }' BBS-list

これに、`BBS-list'の最初のレコードを与えると次のような結果となる。

Field number one: aardvark

文字列中の`:'の後に空白を付けないと、行は次のような形になる。

awk '{ print "Field number one:" $1 }' BBS-list

そしてこれを`BBS-list'で実行すると最初のレコードでは次のようになる。

Field number one:aardvark

文字列の連接が明確な演算子を持っていないので、連接を行なうアイテムをカッコで 囲んで連接が確実に行なわれることを保証することがしばしば必要となる。たとえば 次のようなコードではfilenameを連接するということが明確になっ ていない。

file = "file"
name = "name"
print "something meaningful" > file name

これは次のように書く必要がある。

print "something meaningful" > (file name)

連接を使うときには、いつでもカッコで連接の全体を囲むことを勧める (とくに`='の右辺のオペランドであったりしたときには)。

比較式

比較式は、等しいかどうかなどを調べるために文字列や数値に対しての比較で ある。それらはCのスーパーセットになっている関係演算子を使用して書かれ ている。演算子の例を以下に挙げよう。

x < y
xy未満のときに真。
x <= y
xy以下のときに真。
x > y
xyより大きいときに真。
x >= y
xy以上のときに真。
x == y
xyと等しいときに真。
x != y
xyと等しくないときに真。
x ~ y
文字列x が正規表現 yにマッチするときに真。
x !~ y
文字列x が正規表現 yにマッチしないときに真。
subscript in array
配列arrayの要素に、subscriptがあるときに真。

比較式は真のときに1、偽のときに0の値になる。

比較を行なうときのgawkの使用するルールは、POSIX 標準ドラフトの 11.2に 基づいている。 POSIX の標準では、" +2"のような数値のように見える 文字列である、数値文字列の概念を導入した。

比較演算が行なわれるときに、gawkは比較されるオペランドが最後に使用さ れたときではなく、最後に代入されたときに注目してオペランドの型を決める (セクション 数値と文字列値を参照)。オペランドがフィールド変数や、 コマンドライン引数、splitによって作られた配列の要素、環境変数などのよ うな"外部"からのものであった場合、型は「不明」となる。このケースにおいての み、オペランドが数値文字列であったときに文字列、数値の両方として扱われる。も し、比較式のオペランドの少なくともひとつが数値としてみることのできない文字列 であった場合、文字列同士として比較が行なわれる。数値であるオペランドは CONVFMTの値を使って文字列に変換される (セクション 文字列と数値の変換を参照)。 片方のオペランドが数値であり、もう片方が数値としても文字列としても見ることの できるような場合、gawkは数値比較を行なう。両方のオペランドが数値でも 文字列でもある場合は数値として比較を行なう。文字列の比較は文字列の最初からキャ ラクタごとの比較で行なわれる。したがって、 "10""9"よりも小 さい、ということになる。二つの文字列が他方の前の部分に等しいような場合、つま り "abc""abcd"の比較では、短い方の文字列 "abc" がよ り小さい、と認識される。

以下にgawkがどのように比較を行ない、どのような結果となるのかの 例をいくつか挙げる。

1.5 <= 2.0
数値の比較(真)
"abc" >= "xyz"
文字列の比較(偽)
1.5 != " +2"
文字列の比較(真)
"1e2" < "3"
文字列の比較(真)
a = 2; b = "2"
a == b
文字列の比較(真)
echo 1e2 3 | awk '{ print ($1 < $2) ? "true" : "false" }'

この例では`false'が出力される。なぜなら$1$2の両方が数 値文字列であり、文字列でもあり数値でもあるので数値として比較が行なわれたから である。

比較ルールと数値文字列を使用する目的は、正しい動作を、驚くようなことができる だけ少なくなるように行なわせるということである。

文字列の比較と、正規表現の比較は非常に異なっている。 例を挙げると、

$1 == "foo"

この式はカレント入力レコードの最初のフィールドが`foo'であるときに 1ある いは真の値を持つ。対照的に、

$1 ~ /foo/

この式は最初のフィールドに`foo'が含まれているもの、例えば `foobar' であれば式の値は1となる。

`~' 演算子や `!~'演算子の右側にくるオペランドは 固定正規表現(/.../)でもあり、通常の式でもある。 これは、ちょうど文字列としての式の値が動的正規表現であるということと 同じである (セクション 正規表現の使い方を参照).

最近のawkの実装では、 スラッシュで囲まれた固定正規表現はそれ自体が式である。 /regexp/という正規表現は比較式の省略形である。

$0 ~ /regexp/

一部の文脈においては、gawkの行う構文解析で混乱させないために、正規表 現の周りをカッコで囲む必要があるかもしれない。たとえば(/x/ - /y/) > thresholdという記述は許されないが ((/x/) - (/y/))> thresholdは正しく 構文解析される。

/foo/$0 ~ /foo/の省略形ではないという場所がひとつある。それ は`~' 演算子か`!~'演算子の右辺である! セクション 定数式を参照.

論理式

論理式は比較式やマッチング式を論理演算子(`||')や (`&&')、 (`!')を用いて繋げたものである。論理式全体の真偽は各部分式の真偽値の組み 合わせによって決定される。

論理式は、比較式やマッチング式を記述できるところであればどこでも記述すること ができるし、ifwhiledofor といった文のな かで使うこともできる。論理式は真のとき1、偽のとき0の値を持ち、その結果を変数 に格納したり、算術式に使うこともできる。

それに加えて、それぞれの論理式は正しい論理パターンであるのでルールの実行を制 御するパターンとして使うこともできる。

以下に三つの論理演算子と、それを使った例を挙げる。これらの比較式の例は、式の 変わりにパターンの中で同じ論理演算子をつかった論理パターンの例に似ている。 (セクション 論理式とパターンを参照).

boolean1 && boolean2
boolean1boolean2の両方ともが真のときに真となる。たとえば、次 の例ではカレント入力レコードに`2400'`foo'の両方が含まれている ときにそのレコードが出力される。
if ($0 ~ /2400/ && $0 ~ /foo/) print
部分式boolean2は、boolean1が真であったときにのみ評価が行なわれる。 このことによって、boolean2が副作用を持つ式であったときに違った結果にな るようにすることもできる。たとえば $0 ~ /foo/ & ($2 == bar++)といった式では、`foo'がレコード中に 存在しなかった場合には変数barはインクリメントされない。
boolean1 || boolean2
boolean1boolean2の少なくともどちらか一方でも真であれば論理式 全体が真となる。たとえば、次の例では `2400'`foo'のどちらか一方、 あるいはその両方が入力ファイル`BBS-list'からの入力レコード中にあったと きにそのレコードを出力する。
awk '{ if ($0 ~ /2400/ || $0 ~ /foo/) print }' BBS-list
部分式boolean2は、boolean1が偽であったときにだけ評価が行なわれる。 このことにより、boolean2が副作用を持っていたときには異なった結果をもた らすこともある。
!boolean
booleanが偽であるときに真となる。たとえば、次の例では入力ファイル `BBS-list'からの入力レコード中で文字列`foo'含まないレコ ードを出力する。
awk '{ if (! ($0 ~ /foo/)) print }' BBS-list

代入式

代入は変数に新たな値を設定する式である。例えば、変数zに1をセッ トするには次のようにする。

z = 1

この式が実行された後では変数zの値は1になり、代入前のzの値は失 われる。

文字列も同じ様に代入を行うことができる。例えば、次の例では messageと いう変数に"this food is good"という値が格納される。

thing = "food"
predicate = "good"
message = "this " thing " is " predicate

(この例はまた、文字列の連接も説明している)

`='代入演算子と呼ばれる演算子の中でもっとも単純なもので、右辺の 値をそのまま変更せずに代入する。

大部分の演算子(加算、連接、など)は、値を計算する以外になんの作用も持たない。 もし、(計算された)その値を無視するならば、それは演算子を使わなかったのと同 じ結果となるだろう。しかし代入演算子は、値を生成し、その値を無視したとしても 代入操作は変更された値を自分に格納する。これは副作用と呼ばれる。

代入の左辺は変数(セクション 変数を参照)を必ずしも必要とせず、それはフィールド (セクション フィールド構成の変更を参照) や配列の要素 (セクション awkにおける配列を参照)であってもよい。これらは総称して 左辺値と呼ばれ、代入演算子の左辺に置くことができる。右辺にはどのような 式、特定の値を代入する式やフィールド、配列要素でも、を置くことができる。

重要なことは、変数は常に同じ型であるというわけではないという事である。変数の 型は単純に、その時点で格納している値によって決定される。次に挙げるプログラム の断片では、変数fooは最初は数の値を持ち、その後は文字列値を持っている。

foo = 1
print foo
foo = "bar"
print foo

二番目の代入文でfooに文字列値を与えたときに、それ以前の数の値は失われ る。

代入はそれ自身の値(代入された値)を持つ式である。従って、z = 1は1と いう値を持つ式である。この結果、多重代入を記述することもできる。

x = y = z = 0

この例では、三つの変数全てに0を格納する。なぜならz = 0の値は0であり、 それがyに格納され、さらにy = z = 0の値、つまり0がxに格 納される。

代入は式のどこででも使うことができる。例えばx != (y = 1)という記述は 正しく、これはy に1をセットし、それからxが1と等しいかどうかを テストする。しかし、このスタイルはプログラムを読みにくくするものである。 one-shot programを除いては、このようなネストした代入を取り除くように書きなお すべきである。これは決して難しいことではない。

`='は別として、その他の代入演算子は変数の(代入前の)古い値と演算を行う。 例えば、`+='という演算子は右辺値を変数の古い値と加算して新しい値を計算 する。従って、次の例はfooの値に5加えるということになる。

foo += 5

これは次のように記述したものと同じである。

foo = foo + 5

`+='という演算子を使ったことによりプログラムの意味が明確になる。

以下に、算術代入演算子を列挙する。これらの演算子は、右辺の式の値を数値に変換 して扱う。

lvalue += increment
lvalueの値にincrementを加え、それをlvalueの新たな値とする。
lvalue -= decrement
lvalueの値からdecrementを減じる。
lvalue *= coefficient
lvalue の値にcoefficientを掛ける。
lvalue /= quotient
lvalue の値をquotientで割る。
lvalue %= modulus
lvaluemodulusで割ったときの剰余をlvalueにセットする。
lvalue ^= power
lvalue **= power
lvaluepower乗した値をlvalueにセットする。 (^=という演算子だけが POSIX で定義されている)

増減演算子

増減演算子(increment operator)は変数の値を1増やすか、1減らすかする。 この演算子は代入と同時に使うこともでき、 増減演算子はそういった場合に awk言語に対して何の影響も及ぼさないが、非常によく行なわれることを省略 して記述することができる。

1を加える演算子は`++'と記述する。この演算子は変数のインクリメントを、そ の値を得る前、得た後のどちらでも行える。

vに対して先にインクリメントを行うには++vと記述する。これ はvの値に1を加えて、新しい値がこの式の値となる。 v += 1と いう代入式はこれと全く同じである。

変数の後に`++'を記述したものはポストインクリメントと呼ばれる。これは変 数の値をインクリメントするが、先ほどと違って、インクリメント式自体の値は変数 の古い値である。従って、fooの値が4のとき、foo++という式の値は4 であるが foo の値は5に変更されている。

ポストインクリメントのfoo++(foo+= 1) - 1という記述とほぼ同じ であるが、完全に同じというわけではない。それは、awkでの数値は全て浮動 小数点数だからである。浮動小数点数では、 foo + 1 - 1fooと同 一ではない。しかし、かなり小さな数(一兆未満)しか扱わない限りはこういった違い はごく僅かである。

あらゆる左辺値はインクリメントすることができる。フィールド、及び配列要素は変 数と同じ様にインクリメントが行われる。(フィールドの参照と、変数のインクリメ ントを同時に行いたいときには `$(i++)'を使う。この括弧はフィールド参照演 算子`$'の優先順位の為に必ず付けなければならない。)

デクリメント演算子`--'`++'と同じ様に動作するが、加算ではなく、1 を減算する。`++'と同じく、左辺値の前に置いてプリデクリメントで使用した り、左辺値の後ろに置いてポストデクリメントで使用することができる。

次にインクリメント、デクリメントの簡単な説明をする。

++lvalue
この式はlvalueをインクリメントし、インクリメント後の値をこの式の値とす る。
lvalue++
この式はlvalueの内容をインクリメントする。この式の値はインクリメントす る前の古いlvalueの値となる。
--lvalue
++lvalueと似ているが、加算ではなく減算を行う。 ++lvalueを減じ、その結果が式の値となる。
lvalue--
lvalue++と似ているが加算ではなく減算を行う。 lvalueを減じ、式の値はデクリメントする前の古い値となる。

文字列と数値の変換

awkプログラムの文脈により、必要に応じて文字列を数値に変換したり数値を 文字列に変換したりする。例えば、foo + barという式があったときに、 foobarの値(もしくは両方)が文字列であった場合、その値は加 算が行われる前に、数値に変換される。逆に文字列連結中で数値があった場合にはそ れは文字列に変換される。例を挙げると、

two = 2; three = 3
print (two three) + 4

この例は数値の27を出力する。変数 twothreeの数としての値は 文字列に変換され、それが連結される。その結果得られた文字列は再度 23という数 に変換され、それに4が加えられる。

何かの理由で数を強制的に文字列に変換したいときは、空文字列をくっつける。 逆に文字列を強制的に数に変換するには、文字列に0を加える。

文字列の頭の方に数字列がついているような文字列は、文字列から数値に変換される。 "2.5"は2.5に、"1e3"は1000に変換され、"25fix"は数の値と して25を持つ。正しい数として認識できない文字列は0に変換される。

数値の文字列への変換のルールは組み込み変数CONVFMT (セクション 組込み変数を参照)によって制御される。 数値は関数sprintf(セクション 組込み関数を参照) で書式指定文字列にCONVFMTが渡されたのと同じ様に変換される。

CONVFMTのデフォルトの値は"%.6g"であり、これは値を最低6文字ある として変換する。一部のアプリケーションのために、この精度を変更したいと考える かも知れない。最近のマシンの大部分では倍精度実数は十進数で16から17桁の精度があ る。

CONVFMT に、sprintfで通常の浮動小数点数を指定しているような文 字列ではないものをセットした場合、おかしな結果となるだろう。例えば書式文字列 の`%'を忘れた場合には、全ての数値は同じ文字列定数に変換される。

特別な場合として、数値が整数であった場合には変換した結果の文字列は 常に 整数のものとなり、CONVFMTの値に左右されない。次のようなプログラムの断 片があったとすると、

CONVFMT = "%2.2f"
a = 12
b = a ""

bの値は"12"であり、"12.00"ではない。

POSIX の標準以前には、awkは数値から文字列への変換の為に OFMTの 値を使用していた。 OFMTprint文で数値を出力するときの書式を指 定する。 CONVFMTは、出力するときと、変換するときを区別するために導入 された。CONVFMTOFMTの両方とも、デフォルトの値は"%.6g" である。多くの場合、古いawkはその挙動を変えないだろう。しかし、この様 なOFMTの使用は、プログラムを他の awk処理系 に持っていくような場合には、常にそのことに注意せねばならない。こういった場合、 プログラムを修正するよりもgawkそれ自体を移植することを勧める。

数値と文字列値

このマニュアルの大部分を通じて、awkでの(定数や、フィールド、変数など の) 値は数値か文字列のいずれかであるとされてきた。これは通常使うときにはどち らか片方のみであるので、都合のよい考え方である。

実際のところ、awkでの値は文字列であると同時に数値であってもよい。内部 的には、awkは値を文字列、数値、そしてそのどちらかとして正しい値である かを示す、もしくはどちらの場合においても正しい値であるという情報を保持してい る。

両方の値を記録しておくというのは、正確な数値計算をするために重要である。次の ような例を考えてみよう。変数は文字列値を、最初に文字列として使われたときに得る ことができ、その文字列値は新たな値が代入されるまで使うことができる。従って、 数値としての値のみを持つ変数は何度使われたとしても一回だけ文字列を表すように するだけでよい。数値としての値が正しいものであり続ければ、もし変数が後で数値 演算に使われたとしても数値への再変換は行う必要はない。

両方の値を記憶しておくというのは特に、数値演算の精度においては重要である。次 の例をみてみよう。

a = 123.321
CONVFMT = "%3.1f"
b = a " is a number"
c = a + 1.654

変数aは連接で文字列値を受け取り、それをbに代入する。 a の文字列値は"123.3"である。文字列に変換するときに数値が失われた場合、 それ以前の文で使っていた aの数値の情報は失われてしまう。 cには 124.975ではなく、124.954が代入される。このようなエラーは即座に計算され、数値 計算の障害となる。

一度数値が文字列値に変換されると、その(文字列としての)値は新しく代入が 行われるまで保持されている。 CONVFMT(セクション 文字列と数値の変換を参照) を変更しても、古い文字列値がまだ使われる。例えば、

BEGIN {
    CONVFMT = "%2.2f"
    a = 123.456
    b = a ""                # `a'が文字列値を持つようにする
    printf "a = %s\n", a
    CONVFMT = "%.6g"
    printf "a = %s\n", a
    a += 0                  # `a' が数値のみになるようにもどす
    printf "a = %s\n", a    # `a' を文字列として使う
}

このプログラムは`a = 123.46'を二回出力し、その後で `a = 123.456'.

セクション 文字列と数値の変換を参照, に 数値データからどのように文字列値を作るかの規則が記述されている。

条件式

条件式は三つのオペランドをとる特殊な式である。この式は、ある一つの式の 値によって二つの異なった式のうちどちらか一つを選択するのに使用できる。

条件式はCのそれと同じ様に次のような形で記述される。

selector ? if-true-exp : if-false-exp

三つの部分式の内、最初のselectorは常に最初に計算され、その値が"真" (0でなく、nullでもない)であれば、次に if-true-expを計算し、その値が 式全体の値となる。 "真"でなかった場合には、次にif-false-expを計算し、 その値が式全体の値となる

例えば、次の式はxの値の絶対値を作る。

x > 0 ? x : -x

条件式が計算される毎に、if-true-expif-false-expのどちらか一 つだけが計算され、もう一つは無視される。このことは、式が副作用を持っていると きには重要なことである。例えば、次に挙げる条件式は配列aもしくはb の添字iの要素を取りだし、iをインクリメントする。

x == y ? a[i++] : b[i++]

この例ではiのインクリメントを一回しか行わない。それは、この式全体が実 行される度に、二つのインクリメント式のうちどちらか一つが実行され、もう片方は 実行されないからである。

関数呼び出し

関数とは計算を特定する名前である。名前があるので、プログラム中の任意の 場所で呼び出すことができる。例えば、sqrt関数は、数値の平方根を計算す る。

ある固有の関数群は組み込みであり、全てのawkプログラムで使うこと ができる。 sqrt関数はそのうちの一つである。 セクション 組込み関数を参照.に組み込み関数のリストと、関数の説明があ る。組み込み関数に加え、プログラムのどこかで使うためにユーザーが関数を定義す ることができる。これについては、 セクション ユーザー定義関数を参照.

関数を使うには、関数名とそれに続く括弧で囲まれた引数リストからなる 関数 呼び出し式によって行う。引数は関数が計算を行う為に与えられる生のデータであ る。二個以上の引数がある場合には、引数の間にカンマを置く。引数がない場合には `()'を関数名に続けて書く。例を挙げる。

sqrt(x^2 + y^2)      # 引数一つ
atan2(y, x)          # 引数二つ
rand()               # 引数なし

関数名と、開き括弧の間には空白を置いてはいけない! ユーザー定義関数 の名前は変数名と同じ様に見え、空白は変数と括弧の中の式との連結のように見せて しまう。括弧の前の空白は組み込み関数には無害なものであるが、ユーザー定義関数 を使用するときに、間違って余計な空白を入れないようにするには、常に関数名と開き 括弧の間を空けないようにするのが最良の方法だろう。

個々の関数にはその関数固有の数の引数がある。例えば、sqrt関数は、呼び 出し時に必ず平方根を計算するための一つの数値の引数がなければならない。

sqrt(argument)

一部の組み込み関数では最後の引数を省略することができ、省略した場合には適当な デフォルトの値が使われる。詳しくはセクション 組込み関数を参照.を参照。 ユーザー定義関数の呼び出しで引数を省略した場合、そのような引数はローカル変数 として扱われ、空文字列に初期化される (セクション ユーザー定義関数を参照).

他の式と同様に関数呼び出しも値を持ち、その値は与えた引数に応じて関数が計算し た結果である。例えば、sqrt(argument) の値は与えた引数の平方根で ある。関数は変数への代入や入出力の実行のような副作用を持つことができる。

次の例では、一行当たり一つの数値データを読み取り、読み取った値と、その平方根 を一行に出力する。

awk '{ print $1, "の平方根は", sqrt($1) }'

演算子の優先順位(演算子のネストの仕方)

演算子優先順位は一つの式の中で異なった演算子があったときに、どのように 演算子をまとめるかを決定する。例えば、`*'`+'よりも優先順位が高 く、従ってa + b * cbcを掛けて、それにaを 加える。つまり、 a + (b * c)の様に解釈される。

演算子の優先順位は、括弧を使うことによって無視することができる。優先順位規則 は括弧を書いた通りであると考えることができる。事実、通常使われないような演算 子の結合があるときに、常に括弧を使うのは賢いやり方である。なぜなら、他の人が プログラムを読んだときに、その場合の優先順位を思い出せなかったりあるいは自分 自身が忘れてしまったりするからである。陽に括弧を使うということは、このような ミスをしないような助けになる。

優先順位が同じ演算子を一緒に使った場合、代入、条件式、そしてべき乗演算子を除 けば左側からまとめられる。従って、a - b + c(a - b) + cに、 a = b = ca = (b = c)に解釈される。

単項で前置される演算子の優先順位は、それ単独で使うのと同じ様に、一番深いとこ ろが最初に解析されるので、あまり意味のないことである。それはただ一通り、にし か解釈できないからである。従って、$++i$(++i)と解釈されるし、 ++$x++($x)と解釈される。しかし、オペランドに他の演算子が続 いているような場合には、単項演算子の優先順位が意味を持ってくる。つまり、 $x^2($x)^2であるが、-x^2-(x^2) であるとい うことである。これは、`-'の優先順位が`^'よりも低く、 `$'が全 体で最も高い優先順位であるからである。

以下にawkの演算子を優先順位の低いものから並べる。

assignment
`=', `+=', `-=', `*=', `/=', `%=', `^=', `**='. これらの演算子は右結合する (`**=' 演算子はPOSIXでは定義されていない)。
conditional
`?:'. この演算子は右結合する
"または"
`||'.
"かつ".
`&&'.
array membership
`in'.
マッチング
`~', `!~'.
relational, and redirection
関係演算子とリダイレクションは同じ優先順位である。 `>'の様なキャラクタ は、関係演算子としてもリダイレクションとしても使われる。この両者の区別は文脈 によって決定される。 関係演算子には `<', `<=', `==', `!=',`>=', `>'がある。 入出力リダイレクトの演算子には`<', `>', `>>', `|'がある。 print文やprintf文中のリダイレクション演算子は、式ではなく文の レベルに属している。リダイレクションは他の演算子のオペランドとなる様な式を生 成しない。その結果、リダイレクションをより優先順位の低い演算子のそばに括弧な しで記述するということは意味がない。 `print foo > a ? b : c'はシンタッ クスエラーとなる。
concatenation
連接を指示するための特別なトークンはない。 オペランドを単純に並べて記述すればよい。
加算、減算
`+', `-'.
乗算、除算、剰余
`*', `/', `%'.
単項のプラス、マイナス、 "否定"
`+', `-', `!'.
べき乗
`^', `**'. これらの演算子は右優先でグループ化される (`**' 演算子はPOSIXでは定義されていない)。
increment, decrement
`++', `--'.
フィールド
`$'.

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