組み込み関数とはawk
プログラムで常に呼び出す事のできる関数である。
この章ではawk
の全ての組み込み関数を定義する。一部のものは別のセクショ
ンで説明がされているが、便宜のためここでも簡単にまとめてある。
(ユーザーは自分で新たに関数を定義する事もできる
セクション ユーザー定義関数を参照.)
組み込み関数を呼び出すには、関数の名前に続けて括弧で囲まれた引数を書けばよい。
例えばatan2(y + z, 1)
は関数atan2
を二つの引数で呼び出す。
組み込み関数の名前と、開き括弧の間にある空白は無視される。しかし、そういった 空白は使わないようにすることを勧めたい。ユーザー定義の関数ではこのような空白 を許されておらず、関数名の直後に空白をおかないという単純なやり方でそのような 間違いを簡単に見つけ出せる。
組み込み関数はそれぞれ、特定の数の引数を受け取る。多くの場合、組み込み関数に 対して余計に多く渡された引数は無視される。引数が省略されたときのデフォルトの 扱いは個々の関数毎に決められている。
関数が呼び出されるとき、関数の実引数は実際に関数が呼び出される前に完全に評価 され、式が作り出される。例えば次のようなコードでは
i = 4 j = sqrt(i++)
変数i
は、sqrt
に対する実引数の値として4がセットされて関数が呼ば
れる前に 5がセットされる。
次に組み込み関数の全リストを挙げる。
int(x)
int(3)
は 3、 int(3.9)
は 3、 int(-3.9)
は
-3、そして int(-3)
は -3 となる。
sqrt(x)
sqrt(4)
は2である。
exp(x)
log(x)
sin(x)
cos(x)
atan2(y, x)
y / x
のアークタンジェントを返す(単位はラジアン)。
rand()
rand
の返す値は0から1の範囲の数であり、0と1は含まれない。
しばしば整数の乱数を必要とするだろうが、次に n未満の非負の整数の乱数を
返すユーザー定義関数を挙げる。
function randint(n) { return int(n * rand()) }この例では、掛け算で0より大きくn未満の実数を作り出す。それを(
int
を使って)0からn - 1
の間の整数にする。
次の例は先ほどのものと同じ様な1からnの間の整数を返す関数を使っている。
このプログラムはレコード入力の度に新しい乱数を出力する。
awk ' # サイコロをシミュレートする関数 function roll(n) { return 1 + int(rand() * n) } # 三つの六面体サイコロを振り、合計を出力する { printf("%d ポイント\n", roll(6)+roll(6)+roll(6)) }'ノート:
awk
を走らせるたびにrand
は、同じ場所、もしくは
seedから数値を作り出す。このことはプログラムを実行する度に同じ結果が生
成されるということである。その数値はひとつのawk
プログラムの中ではラン
ダムであるけれども走らせるごとに予想できるものである。これはデバッグには便利
であるけれども、使う度毎に違う結果を必要とするような場合には実行する毎に乱数
の種を違ったものにしなければならない。それを行うにはsrand
を使用する。
srand(x)
srand
は乱数を生成するための出発点、もしくは種の値として
xをセットする。
それぞれの種は各々特定の"乱数列"を導き出す。従って、乱数の種として同じ値を
二度目にセットしたとすると、同じ"乱数列"を得ることになる。
srand()
の引数xを省略した場合、乱数の種としてその時点の日時が使
用される。この方法は予測できないような乱数列を得られる。
srand
の返す値は以前使われていた乱数の種である。これによって以前の乱数
系列をもう一度作り出すことが簡単になる。
このセクションにある関数は一つ以上の文字列を検索したり変更したりするものである。
index(in, find)
awk 'BEGIN { print index("peanut", "an") }'`3'を出力する。findが見つからなかった場合、
index
は0を返す。
(awk
での文字列の添字は1から始まると言うことを思い出して欲しい)
length(string)
length("abcde")
は5であるが、length(15 * 35)
の結果は 3である。
それは15 × 35 = 525で、この525は三つのキャラクタからなる `"525"'という
文字列に変換されるからである。
引数が省略された場合、length
は$0
の長さを返す。
古いバージョンのawk
では、length
関数を括弧なしで呼ぶことができ
る。しかしそれは、 POSIX の標準では好ましくない(deprecated)とされる。このことは、プログラム中
でこういった書き方が将来のバージョンでは使えなくなるかも知れないということで
ある。従って、awk
プログラムの移植性を最大にするために括弧を常に書くべ
きである。
match(string, regexp)
match
関数はstringから、正規表現regexpにマッチする部分文字
列の中で、最も左にあり、もっとも長い部分文字列を検索し、部分文字列が始まる場
所を返す(stringの最初から始まっていれば1)。マッチするものが見つから
なかった場合、0が返る。
match
関数は組み込み変数のRSTART
にインデックスをセットし、同様
に組み込み変数RLENGTH
にマッチした部分文字列の長さをセットする。マッチ
しなかった場合には、RSTART
には0が、RLENGTH
には -1がセッ
トされる。
例えば、
awk '{ if ($1 == "FIND") regex = $2 else { where = match($0, regex) if (where) print "Match of", regex, "found at", where, "in", $0 } }'このプログラムは変数
regex
に格納されている正規表現にマッチする行を探す。
この正規表現は変更することができる。ある行の最初の単語が`FIND'であった
場合、 regex
はその行の二番目の単語に変更される。従って、次のようなデー
タを与えると
FIND fo*bar My program was a foobar But none of it would doobar FIND Melvin JF+KM This line is property of The Reality Engineering Co. This file created by Melvin.
awk
は次のように出力する:
Match of fo*bar found at 18 in My program was a foobar Match of Melvin found at 26 in This file created by Melvin.
split(string, array, fieldsep)
array[1]
に、二番目
の要素は array[2]
に格納され、以下の要素も同様である。三番目の引
数fieldsepの文字列値は、 stringを分割する場所を指定する
(FS
が入力レコードを分割する場所にマッチする正規表現であるように)正
規表現である。 fieldsepが省略されると、FS
の値が使われる。
split
は作り出された要素の数を返す。
split
関数はまた、入力行をフィールドに分割するとの同じ様なやり方で文字
列を分割する。例えば、
split("auto-da-fe", a, "-")これは`-'をセパレータとして、`auto-da-fe'という文字列を三つのフィ ールドに分割し、配列
a
の要素を以下のようにセットする。
a[1] = "auto" a[2] = "da" a[3] = "fe"
split
を呼び出して返ってくる値は3である。
入力フィールドを分割するときと同じ様に、fieldsepの値が" "
であ
る場合には先頭や末尾にある空白は無視され、要素は空白で区切られる。
sprintf(format, expression1,...)
printf
がその引数を渡されたときに出力するであろう文字列を
(出力はせずに)返す。
(セクション printf
文を使った Fancier Printingを参照).
例えば、
sprintf("pi = %.2f (approx.)", 22/7)これは
"pi = 3.14 (approx.)"
という文字列を返す。
sub(regexp, replacement, target)
sub
関数はtargetの値を変更する。検索する値は文字列でなければなら
ず、そしてそれは regexpで与えられる正規表現にマッチする部分文字列の中
で一番左にあり、長さが一番長いものである。文字列全体の内マッチしたテキストは
replacementで置き換えられる。
この関数は独特である。それは、targetが単に値を計算するのに使われるので
はなく、式ではないということからくる。 targetは変数、フィールド、配列
の参照のように変更された値を格納できるものでなければならない。この引数が省略
された場合にはデフォルトとして$0
が使用される。
例を挙げると
str = "water, water, everywhere" sub(/at/, "ith", str)この例は
str
に"wither, water, everywhere"
をセットし、その
中で最も左にあり、もっとも長い`at'を`ith'に置き換える。
sub
関数は置き換えを行った数(つまり1か0のいずれか)を返す。
replacement中にスペシャルキャラクタ`&'があると、それはregexp
にマッチした部分文字列を表す。 (もしこの正規表現が二つ以上の文字列にマッチす
るのならば、 `&'が表す部分文字列が変化するだろう) 例えば、
awk '{ sub(/candidate/, "& and his wife"); print }'各入力行で最初に現れる`candidate'を`candidate and his wife'に 変更する。 別の例を挙げよう。
awk 'BEGIN { str = "daabaaa" sub(/a*/, "c&c", str) print str }'この例では`dcaacbaaa'が出力される。これは`&'は非文字定数として扱わ れ、最左最長の規則に従っている為である。 スペシャルキャラクタ(`&')の効果はその前にバックスラッシュを付けることに よって抑制することができる。例によって、文字列中に一つのバックスラッシュを入 れるためにはバックスラッシュを二つ続けて書かなければならない。従って、置換文 字列中に`&'という文字を含ませるには`\\&'と記述する。次に挙げる例は 各行で最初に現れる`|'を`&'で置き換える。
awk '{ sub(/\|/, "\\&"); print }'ノート:上述のように、
sub
の三番目の引数は左辺値でなければならな
い。一部のawk
には三番目の引数として左辺値でない式を許すものもある。そ
ういった場合、sub
はパターンを検索し、0か1を返すけれども、置き換え(起
こったとして)の結果は、それを格納する場所がないので失われる。そのような
awk
は次のような式を受け付ける。
sub(/USA/, "United States", "the USA and Canada")しかしこれは
gawk
ではエラーとなる。
gsub(regexp, replacement, target)
sub
と似ているが、gsub
はもっとも長く、最も左にあり、
それぞれが重ならないようなマッチした部分文字列をすべて置換する。
gsub
の`g'は全ての場所で置換を行う"global"を意味する。次の例で
は、
awk '{ gsub(/Britain/, "United Kingdom"); print }'全ての入力レコードで、`Britain'という文字列を全て `United Kingdom' に置き換える。
gsub
関数は置き換えが起こった回数を返す。検索と置換の対象となる変数
targetが省略された場合、入力レコード全体、つまり$0
が使用される。
sub
と同じ様に、`&' と `\'の二つのキャラクタは特殊な意味があ
り、また三番目の引数は左辺値でなければならない。
substr(string, start, length)
substr("washington", 5, 3)
は"ing"
を返す。
lengthが与えられない場合、この関数はstringで start番目から
始まる残りの部分全てを返す。例えば、substr("washington", 5)
は
"ington"
を返す。 lengthがstart番目から文字列の終端までの
長さよりも長い場合も同様である。
tolower(string)
tolower("MiXeD cAsE 123")
は "mixed case 123"
を返す。
toupper(string)
toupper("MiXeD cAsE 123")
は "MIXED CASE 123"
を返す。
close(filename)
system(command)
awk
プログラムに復帰するという動作を行うことを許す。 system
関数
は文字列commandで指定されるコマンドを実行する。その戻り値はコマンドが実
行されたときのリターンステータスである。
例えばawk
プログラム中に次のようなコードを記述すると、
END { system("mail -s 'awk run done' operator < /dev/null") }システムオペレータは
awk
プログラムが入力の処理を終了し、入力終了時の
処理を始めるときにメイルを送信する。
同様な結果をprint
や printf
をパイプにリダイレクトすることで得
ることもできるが、awk
プログラムが対話的であるような場合に、system
はシェルやエディタのような大きな実行プログラムを起動するのに便利である。
一部のオペレーティングシステムではsystem
関数を実装できない。
サポートされていない場合、system
は致命的エラーを引き起こす。
system
多くのユーティリティプログラムはその出力をバッファリングしていて、ディ
スク上のファイルや、ターミナルに出力する情報を、一回のオペレーションで出力す
るのに充分な量になるまで保存している。このことは細かな(出力する)情報が来る
度にいちいち書き出しを行うのに比べてより効果的である。しかし、時としてプログ
ラムに対して強制的にそのバッファを、例えバッファがいっぱいになっていなくても
フラッシュさせる(そのバッファが対応している出力先に対して出力する)必
要がある場合もある。そのようなときはawk
プログラム中でsystem
の
引数を空文字列にして呼び出しを行えばよい。
system("") # 出力のフラッシュ
gawk
はこのようなsystem
関数の使い方を特殊なものとして扱い、空の
コマンドでシェル(あるいは他のインタプリタ)を走らせるようなことはしない。従っ
て、gawk
ではこのような使い方は便利なだけでなく、この使い方が他のイン
プリメンテーションのawk
でも同様に働くのであれば、必要のないシェルを実
行する必要もなくなる。
awk
プログラムの一般的な使い方はログファイルの処理である。ログファイル
はしばしば、ある特定のレコードが書き込まれたタイムスタンプの情報を持っている。
多くのプログラムはtime
システムコールが返した値(ある特定の時点からの経
過秒数)をタイムスタンプに使っている。 POSIX システムでは、それは UTC 1970年
の1月1日0時からの秒数である。
ログファイル等の処理や便利なレポートの作成を簡単にするために、 gawk
は
タイムスタンプに関連した働きをする二つの関数を備えている。これら二つは両方と
もgawk
特有の拡張であり、POSIX 標準では定義されていないし、ほかの
awk
でも使うことはできない。
systime()
strftime(format, timestamp)
systime
関数はログファイルの日付、時間と、プログラムを実行している時点
の日付、時間とを比較することを可能にする。特に、ある特定のレコードが記録され
てからどれくらいたったのかを求めることが簡単になる。それはまた、"seconds
since the epoch"フォーマットを使ってログのレコードを作成することを可能にす
る。
strftime
関数はタイムスタンプを、人間が読み易い情報に変換するのを簡単
にさせる。この関数はsprintf
と似ていて、書式指定でないキャラクタはその
まま文字列として返され、書式指定文字列中で日付や時刻を特定するものがあるとそ
れを置き換える。もし、timestampが省略されると gawk
は代わりに実
行時の時間を使う。
strftime
は、ANSI の標準Cがサポートする以下の書式指定を使用できる。
%a
%A
%b
%B
%c
%d
%H
%I
%j
%m
%M
%p
%S
%U
%w
%W
%x
%X
%y
%Y
%Z
%%
もし変換指定文字が上に挙げたもののひとつでない場合には、その結果は未定義であ
る。 (これは ANSI の標準CではCバージョンのstrftime
のそのような場合の
動作が定義されていないからで、gawk
が使うであろうそのシステムでの
strftime
それならば同様の結果となる。典型的なのは変換指定文字が戻り値の
文字列にないということだろう。)
非公式に、 localeはプログラムを実行する地理的な場所である。例えば、ア メリカ合衆国では1991年9月4日を略して書き表わす普通のやり方は "9/4/91"であ る。ヨーロッパの多くの国ではそれを"4.9.91"のように記述する。したがって、ア メリカにおいては`%x'という指定は `9/4/91'という結果となり、ヨーロッ パでは`4.9.91'という結果となる。 ANSI 標準Cでは大部分のCプログラマーが 使うであろう環境でのデフォルトのCのロカール(locale)を定義している。
パブリックドメインバージョンのstrftime
は ANSIに完全にしたがった形では
書かれていない。そういったものをgawk
のコンパイルのときに使用すれば
(セクション gawk
のインストールを参照.)、次に挙げるような書式指定も
行なうことが可能である。
%D
%e
%h
%n
%r
%R
%T
%t
%k
%l
%C
%u
%V
%Ec %EC %Ex %Ey %EY %Od %Oe %OH %OI
%Om %OM %OS %Ou %OU %OV %Ow %OW %Oy
date
utility.)これらは"代替表現"(alternate representations)であり、
二番目の文字((`%c'や`%C'など)だけが指定に使われる。
これらは認識されるが、それらの通常の意味が使用される
(これらはPOSIXのdate
ユーティリティに従うことを容易にする)。
%v
次の例はstrftime
を使った例である。
最初がCのctime関数のawk
バージョンである。
(これはユーザー定義関数である。
セクション ユーザー定義関数を参照.)
# ctime.awk # # awk による Cライブラリの ctime(3) 関数 function ctime(ts, format) { format = "%a %b %e %H:%M:%S %Z %Y" if (ts == 0) ts = systime() # デフォルトとして現在時刻を使う return strftime(format, ts) }
次の例は、POSIX のdate
ユーティリティの awk
による実装
である。通常は、date
ユーティリティは現在の日付と時刻をよく使わ
れる書式で出力する。しかしながら、`+'で始まる引数を与えた場合には、
date
は書式指定でない文字列を書式指定の文字がくるまでそのまま標準出力
に送る。たとえば、
date '+Today is %A, %B %d, %Y.'
これは次のような出力を行なう。
Today is Thursday, July 11, 1991.
awk
バージョンの date
ユーティリティはこうなる。
#! /usr/bin/gawk -f # # date -- P1003.2 Draft 11 の'date' コマンドの実装 # # Bug: -u 引数を認識しない。 BEGIN \ { format = "%a %b %e %H:%M:%S %Z %Y" exitval = 0 if (ARGC > 2) exitval = 1 else if (ARGC == 2) { format = ARGV[1] if (format ~ /^\+/) format = substr(format, 2) # 先行する+を取り除く } print strftime(format) exit exitval }