awk
awk
の基本的な機能は、ファイルからあるパターンを含んでいる行(もし
くは他のテキストの構成単位)を検索することである。ある行がパターンの一つ
にマッチしたとき、awk
は特定のアクションをその行に対して実行する。
awk
はこのようにして入力ファイルの最後の行までそれぞれの行を処理し
続ける。
awk
のプログラムは他の大部分の言語とは異なっていて、data-driven
である。これは処理したいと思うデータについて記述し、さらにそれを
見つけたときにどのようなことをするのかということについて記述する。という
ことである。他のほとんどの言語は手続き型(procedural)である。それら
においては、事細かに、プログラムの各ステップ毎にどのようにするかを記述し
なければならない。手続き型言語を使用しているときは、あなたがプログラムで
処理しようとしているデータがどのような構造をしているかを明確に記述するこ
とは、一般的には簡単ではない。このため、awk
プログラムはしばしば書
くのも、読むのもやさしいということになるのである。
awk
を実行したときにawk
がどのように動作するかをawk
プログラムで指定できる。プログラムはルールの集まりからなる(関数定義も含ま
れるが、高度な機能なので今のところは無視する。
セクション ユーザー定義関数を参照.)。
個々のルールはある特定のパターンを探し、見つかったパターンで定義されたア
クションを実行する。
文法的には、ルールはパターンとそれに続くアクションから構成される。アクショ
ンはカーリーブレースによってアクションと区切られる。ルールは一般的には改行
によって区切られる。その結果、 awk
プログラムは以下のような形式と
なる。
pattern { action } pattern { action } ...
awk
言語は何年にも渡って発展してきた。その詳しい説明は
セクション awk
の発展を参照
で述べられている。このマニュアルで説明されている言語は
ほとんどが"new awk
"として知られているものである。
このため、多くのシステムでは複数のバージョンのawk
が存在する。一部
のシステムはオリジナルバージョンのawk
言語のインプリメントである
awk
ユーティリティと、新しいバージョンであるnawk
ユーティリテ
ィを持っている。他の一部は"古いawk
"であるoawk
を持ってい
る。残りのものは一つのみ、通常は新しいほうをawk
として
持っている。(3)
重要な事は、このことによって、あなたが書いたプログラムをどのバージョンの
awk
で実行すればよいかということを知ることが難しくなるということで
ある。ここで私達ができる最善のアドバイスは、あなたのシステムのドキュメン
トを確かめて欲しい。ということである。gawk
に対してと同じくらい
awk
, oawk
, nawk
を見て欲しい。あなたが使っているシス
テムには新しいバージョンのawk
があり、あなたのプログラムを実行する
ときにはそれを使ったほうがよい局面があるかもしれない(もちろん、あなたが
このマニュアルを読めば、gawk
を持つ機会があるわけだ!)
このマニュアルを通じて、POSIXでのawk
の実装が備えている
言語の機能を示すときには、単純にawk
という語を使う。GNUでの実装
に特有な機能を示すときにはgawk
という語を使用する。
awk
プログラムの実行の仕方
awk
プログラムを実行するには幾つかの方法がある。
プログラムが短いのならば、下の例のようにawk
を実行するコマンド
に含めてしまうのがもっとも簡単である。
awk 'プログラム' 入力ファイル1 入力ファイル2 ...
プログラムは、先に説明したようにパターンとアクションの並びである
(なぜ引用符が書かれているのかについては)
セクション 使い捨ての一発awk
プログラムを参照.)。
プログラムが長い場合、プログラムをファイルにしてしまい、次のようにして コマンドと一緒に実行するのが一般的には便利である。
awk -f プログラムファイル 入力ファイル1 入力ファイル2 ...
awk
プログラム
一度awk
に慣れ親しんでしまえば、単純なプログラムを
必要とするときにタイプするようになるだろう。
そのようなとき、そんなプログラムはawk
コマンドの
最初の引数として記述できる。このように。
awk 'プログラム' 入力ファイル1 入力ファイル2 ...
プログラムは先に説明したように、 パターンとアクションの並びからなる。
このコマンドはシェルやコマンドインタープリターに対してawk
を
起動させ、プログラムが入力ファイル中のレコードを処理するように指
示するものである。プログラムの周りには引用符があり、これによってシ
ェルは、シェルにとってのスペシャルキャラクタとなるawk
のキャラクタ
を誤って解釈することがなくなる。同時にこれは、シェルに対してプログ
ラムがawk
に対する一つの引数にし、またプログラムが複数行に
渡ることも可能にする。
この書式はawk
プログラムを別のファイルに分ける必要がないので、短い
ものから中程度の大きさのawk
プログラムをシェルスクリプトから実行す
るのに便利である。自己完結した(self-contained)シェルスクリプトは分割されているファイル
を間違った場所に置くことがないので、より信頼性がある。
幾つかの、短い自己完結したプログラムは セクション 便利な一行野郎を参照.にある。
awk '/foo/' files ...
このようなコマンドは 次のものと同じである。
egrep foo files ...
awk
の実行
awk
を入力ファイルなしで実行することもできる。それには
こうコマンドラインでタイプすればよい。
awk 'program'
このとき、awk
はprogramの入力を標準入力にする。
標準入力は通常、あなたが端末からタイプしたものである。
これはあなたがControl-dをタイプしてファイルの終端を
指示するまで続く(他のオペレーティングシステムではファイルの終端を
示すキャラクタは違ったものである。例えばOS/2やMS-DOSでは
Control-zである)。
以下の例にあるプログラムは親切なアドバイスを出力し (Douglas Adamsの The Hitchhiker's Guide to the Galaxyより)、 コンピュータプログラミングの複雑さに対して恐れないようにする (`BEGIN'はまだ説明していない機能である)。
$ awk "BEGIN { print \"Don't Panic!\" }" -| Don't Panic!
このプログラムは何の入力も読まない。ダブルクォートの前にある `\'は、シェルのクォートルールのために、 特にダブルクォートとシングルクォートを混ぜて使う場合に 必要である。
次なる単純なawk
プログラムはcat
ユーティリティを
模倣するものである。これはキーボードからタイプしたものすべてを
標準出力にコピーする(こんなに短いのにちゃんと働くのだ)。
$ awk '{ print }' Now is the time for all good men -| Now is the time for all good men to come to the aid of their country. -| to come to the aid of their country. Four score and seven years ago, ... -| Four score and seven years ago, ... What, me worry? -| What, me worry? Control-d
ときとしてawk
プログラムが非常に大きくなることがある。
この場合、プログラムを別のファイルに分けて置くのが便利である
awk
に対してプログラムの入ったファイルを指定するには
次のようにタイプする。
awk -f ソースファイル 入力ファイル1 入力ファイル2 ...
`-f'はawk
ユーティリティに対してawk
プログラムを
ソースファイルというファイルから受け取るということを指定する。任意
の名前をソースファイルに使うことができる。たとえば、次のようなプロ
グラムを
BEGIN { print "Don't Panic!" }
`advice'という名前のファイルに置くことができ、 次のようなコマンドで使う。
awk -f advice
これは次の例とおなじことである。
awk "BEGIN { print \"Don't Panic!\" }"
こちらは既に説明した
(セクション 入力ファイルなしのawk
の実行を参照)。
大部分のファイル名はシェルのスペシャルキャラクタを含んでいないので、通
常は`-f'で指定するファイル名を引用符で括る必要はない。`advice'
中では、awk
プログラムは引用符で括られていない。引用符をつける必
要があるのはawk
のコマンドライン上でプログラムを与える場合だけで
ある。
もしawk
プログラムのファイルの確認を明確にしたいのなら、ファイル
名に`.awk'という拡張子を追加することができる。これはawk
プ
ログラムの実行には影響を及ぼさないが、"housekeeping"を容易にする。
awk
プログラム
@cindex scripts, executable
一度awk
を学んでしまえば、シェルの`#!' 構文を使って、独立した
awk
スクリプトを書いてみたくなるだろう。多くのUnixシステム
(4)
でこれが可能である(そしていつかはGNUシステムでも)。
例を挙げると、`advice'というファイルを次のようにすることができる。
#! /bin/awk -f BEGIN { print "Don't Panic!" }
このファイルを(chmod
ユーティリティを使って)実行可能にした後で、
シェルから単純に`advice'とタイプするだけで、`awk -f advice'と
タイプしたのと同じようにシステムがawk
を実行するようアレンジする
(5)。
$ advice -| Don't Panic!
自己完結したawk
スクリプトは、
それを使う人がそのプログラムをawk
で書かれたものであることを
知ることなしに起動できるプログラムを書きたいと思うときに便利である。
警告:`#!'の行でawk
のパスの後に
二つ以上の引数を置くべきではない。これをしてしまうと
正しく動作しないだろう。オペレーティングシステムは行の残りの部分
を一つの引数として取り扱い、それをawk
に渡す。
これによって混乱した動作がもたらされる。ありがちなのは、
awk
のusageメッセージの類が出力されることだろう。
一部の古いシステムでは`#!'機構をサポートしていない。 同じ効果を、通常のシェルスクリプトを使って得ることができる。 それにはこのようにすればよい。
: The colon ensures execution by the standard shell. awk 'program' "$@"
このテクニックを使うとき、シングルクォートでプログラムを囲むこと はシェルが解釈するのを防ぐために重要である。もしクォートを取って しまったら、シェルの達人だけしか結果を見通せないだろう。
"$@"
はシェルに対して、(シェルスクリプトに渡された)コマンドライ
ン引数をシェルが解釈することなしにawk
プログラムに渡すようにさせ
る。コロンで始まっている最初の行は、このシェルスクリプトがCシェルを使っ
ているユーザーが起動した場合でもきちんと動くようにするためのものである
(古いシステムすべてでこの手段が有効であるとは限らないが、多くのシステム
で使用できる)。
awk
プログラム中のコメントコメントとはプログラム中で、人が(プログラムを)読みやすくするために含 められるテキストであり、プログラムにとって必要不可欠というものではない。コメ ントはプログラムが書けるところならどこでも置けるが、何の働きもしない。身近な 全てのプログラミング言語はその様な目的のためにコメントを使える様になっている が、それは典型的なプログラムというものは何らかの助けなしには理解するのが非常 に難しいからである。
awk
言語のコメントは`#'で始まり、その行の終わりまで続く。
awk
言語は`#'に続く部分を無視する。
例えば、`advice'に次のように追加を行うことができる。
# This program prints a nice friendly message. It helps # keep novice users from being afraid of the computer. BEGIN { print "Don't Panic!" }
awk
プログラムをキーボードから直接入力しているような場合でもコメント行
を入力することは可能であるけれども、これはあまり有効なことではないだろう。な
ぜならコメントを使う目的が、後日あなたか、あるいは他の人がそのプログラムを
読んだときに理解するのを助けるためだからだ。
警告:セクション 使い捨ての一発awk
プログラムを参照
で言及したように、小規模のプログラムをシングルクォートでくくることが
可能であり、それによってあなたのシェルスクリプトをself-containdな
ものにできる。これを行ったとき、アポストロフィ(シングルクォート)を
コメント中(もしくはプログラムのどこかで)で使ってはいけない。
シェルはそのようなクォートをプログラム全体をくくるクォートとして
扱ってしまう。結果として、通常はシェルがクォートのバランスが
取れていないといったメッセージを出力する。そして、awk
が実際に実行されたならば、構文エラーのような妙なメッセージを
出力するだろう。例を挙げる:
awk 'BEGIN { print "hello" } # let's be cute'
次のプログラムは`BBS-list'という入力ファイルから`foo'という キャラクタの並びを探し出す (キャラクタの並び(string of characters)は、通常文字列(string)と 呼ばれる。stringという語はおそらく "a string of pearls," とか "a string of cars in a train"のような 英語一般に使われる用法に基づくものである)。
awk '/foo/ { print $0 }' BBS-list
`foo'を含む行が見つかると、その行が出力される。これは、 `print $0'がカレント行の出力を意味するからである(代わりに `print'と書いても同じ結果が得られる)。
`foo'を囲むスラッシュ`/'は検索するパターンを表している。こうい
ったパターンは正規表現と呼ばれる。正規表現については後の方で詳しく
述べられる(セクション 正規表現を参照)。
awk
プログラムを引用符で囲んでいるのは、シェルのスペシャル
キャラクタがあっても、それをシェルに解釈させないようにするためで
ある。
プログラムの出力は次のようになる
$ awk '/foo/ { print $0 }' BBS-list -| fooey 555-1234 2400/1200/300 B -| foot 555-6699 1200/300 B -| macfoo 555-6480 1200/300 A -| sabafoo 555-2127 1200/300 C
awk
のルールでは、パターンかアクションのどちらかを省略することができ
るが、両方とも省略することはできない。パターンが省略されると、(そのパター
ンに対応する)アクションはすべての入力行に対して実行される。アクションが省
略されていると、デフォルトのアクションとして(パターンにマッチした)その行
を出力する。
したがって、先の例ではアクション(print
文とそれを囲むカーリーブレー
ス)を省略でき、同じ結果、つまり`foo'とマッチする行を出力する。を得る
事ができる。しかし、カーリーブレースは省略せずにprint
を省略した場合
には何も行わず、行も出力されない。
awk
ユーティリティは、一度のファイル入力で一行だけ入力する。
入力された個々の行に対し
て、awk
プログラムで記述されている各ルールのパターンとの照合
を行う。
パターンとマッチすればアクションが実行され、マッチするパターンが
なければ何も実行されない。
た後でawk
は次の入力行の読み込みを行う(しかし例外はある。
セクション The next
Statementを参照と
セクション The nextfile
Statementを参照)。
この動作はファイルの終端に達するまで繰り返される。
例えばこのawk
プログラムは
/12/ { print $0 } /21/ { print $0 }
二つのルールがある。最初のルールはパターンとして 文字列`12'を、アクションとして `print $0'を持つ。二番目のルールは、 パターンとして文字列 `21'を、アクションとして一番目のルールと同じ `print $0'を持つ。各ルールはペアとなっているブレースによって囲まれてい る。
この awk
プログラムは、文字列12か文字列21を含むすべての行を出力する。
もし、行の中に両方ともあれば、その行はそれぞれのルール毎に出力が
行われるので結果として二回出力されることになる。
このプログラムを`BBS-list' と `inventory-shipped'の 二つのサンプルデータファイルに対して実行した場合の結果はこうなる
$ awk '/12/ { print $0 } > /21/ { print $0 }' BBS-list inventory-shipped -| 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 -| core 555-2912 1200/300 C -| 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 -| sabafoo 555-2127 1200/300 C -| Jan 21 36 64 620 -| Apr 21 70 74 514
`BBS-list' 中の`sabafoo'で始まる行が二回出力されているのは 各ルールで一回ずつ出力されたからであることに注意。
以下の例は、あなたにawk
プログラムの行うことの典型的な
アイデアを与えるためのものである。この例はawk
に対して、
他のユーティリティの出力を要約し、選択し、アレンジするための
方法を示している。まだ説明がされていない機能が使われているが、
(スクリプトの)全てが理解できなくても心配することはない。
ls -lg | awk '$6 == "Nov" { sum += $5 } END { print sum }'
このコマンドはカレントディレクトリにある11月(年は何年でもよい)に最後の修 正がなされたファイルの大きさの合計バイト数を出力する。 (あなたがCシェルを使っ ていた場合、このサンプルを実行するには最初の行の最後にセミコロンとバックス ラッシュを付け加える必要がある。 POSIX に従ったシェル、例えばBシェル であるとか、Bash(GNU Bourne-Again shell)を使っている場合にはサンプルを そのまま打ってみてかまわない)
例の`ls -lg' の部分は、あるディレクトリ中のファイルをそのサイズと 最終修正日付とともにリストアウトするためのコマンドであり、その出力は 以下のような形である。
-rw-r--r-- 1 arnold user 1933 Nov 7 13:05 Makefile -rw-r--r-- 1 arnold user 10809 Nov 7 13:03 gawk.h -rw-r--r-- 1 arnold user 983 Apr 13 12:14 gawk.tab.h -rw-r--r-- 1 arnold user 31869 Jun 15 12:20 gawk.y -rw-r--r-- 1 arnold user 22414 Nov 7 13:03 gawk1.c -rw-r--r-- 1 arnold user 37455 Nov 7 13:03 gawk2.c -rw-r--r-- 1 arnold user 27511 Dec 9 13:07 gawk3.c -rw-r--r-- 1 arnold user 7989 Nov 7 13:03 gawk4.c
最初のフィールドは読み書きの許可フラグ、二番目のフィールドはそのファイルへ リンクしているリンクの数、三番目のフィールドはそのファイルのオーナーのID、 四番目がファイルのグループ、 五番目がそのファイルの大きさをバイトで表したもの、6,7,8番目のフィールドは 最後にそのファイルが修正された月、日、時間である。 最後の9番目のフィールドはファイルの名前である。
このawk
プログラムの$6 == "Nov"
という式は、 `ls -l'の
出力の六番目のフィールドが`Nov'という文字列とマッチするかどうかをテス
トしている。 `Nov'という文字列を六番目のフィールドに持つ行が読み込まれ
るたびに `{ sum += $4 }'というアクションが実行される。このアクション
では、五番目のフィールド(ファイルサイズ)をsum
という変数に足し込ん
でいる。結果として、sum
はパターンにマッチした行のファイルの大きさの
合計を表す(awk
の変数は、自動的に 0で初期化されている)。
ls
の出力から渡される最後の行が処理された後で、END
ルールが実
行され、 sum
の値が出力される。この例では、 sum
の値は80600にな
るだろう。
こういった類の高度なawk
の使い方は、後の方のセクションで述べられて
いる(セクション Overview of Actionsを参照)けれども、その様な使
い方を覚える前にどのように入力が解釈され、どのように出力が表示されるかを
知ったほうがよいだろう。フィールドを操作し、print
文を使うことによ
って、有用なそして華やかな見栄えのするレポートを作成することができる。
awk
の文と行
ほとんどの場合、awk
programの各行は次の例にみられるように独立した文、
あるいは独立したルールである。
awk '/12/ { print $0 } /21/ { print $0 }' BBS-list inventory-shipped
しかし、gawk
は以下に挙げるものに続く改行は無視する。
, { ? : || && do else
その他の場所にある改行は文の終端として認識される。 (`?'と`:' の後
の行の分割はgawk
特有の拡張である `?' と `:'三つのオペランド
を取る条件式であり、詳しい説明は
セクション Conditional Expressionsを参照.)
一つの文を二つの行に改行で分けたいときに、行末にバックスラッシュ`\'を置 くことによって行を継続することができる。このバックスラッシュによる行の継続は どこにでも置く事ができる。たとえ、文字列や正規表現の途中であっても可能である。 例えば
awk '/This regular expression is too long, so continue it\ on the next line/ { print $1 }'
このマニュアルにあるサンプルプログラムでは、通常バックスラッシュに
よる継続を使用しない。なぜなら、gawk
には一行の長さに制限がなく、
継続の必要が全くないからである。また、継続を使わないことによってプログラ
ムがより読みやすくなるということもある。同じ理由によって、サンプルプログ
ラムではほとんどの文を短く保っている。バックスラッシュによる継続は、あな
たのawk
プログラムがコマンドライン上でタイプされるものの代わりに分
割されたソースファイルであるときに非常に便利である。ここで、バックスラッ
シュによる行継続は各awk
処理系の実装に依存するものであることに注意
するべきである。たとえば、文字列定数を行継続を使って分割することを許して
いない処理系がある。したがって、あなたの作成するawk
プログラムの移
植性を最大限に保つためには、正規表現や文字列の途中での行の分割を行わない
ことが最良の手段である。
警告:バックスラッシュによる行の継続はCシェルではこのマニュアルに
書かれている通りには動作しない。 バックスラッシュによる行継続はファイル
に記述されたawk
プログラムや Bourne シェル、Bash(GNU Bourne-Again
shell)等のPOSIX に従ったシェルでのone-shot programsでは働くが、
Cシェル(csh
)ではそうではない! Cシェルの場合はバックスラッシュを改
行の前に二つ続けて書かなければならない。同様に、Cシェルを使っているとき
にはawkプログラムのすべての行の改行をバックスラッシュでエスケープ
しなければならないことに気をつけること。例を挙げよう。
% awk 'BEGIN { \ ? print \\ ? "hello, world" \ ? }' -| hello, world
ここで、`%' や `?'はそれぞれCシェルの一次プロンプトと 二次プロンプトである(標準シェルでは `$'と`>')。
awk
は行指向の言語である。各々のルールのアクションはパターンとして
同じ行に置かねばならない。パターンとアクションを分割した行に置くには、バ
ックスラッシュによる行継続を使わなければならない。
バックスラッシュによる継続とコメントとを混ぜないように気をつけよう。
awk
は`#'を見つけるやいなや、
コメントが始るとみなし、そこから、行の後の
ほうはすべて無視する。例を挙げる。
$ gawk 'BEGIN { print "dont panic" # a friendly \ > BEGIN rule > }' error--> gawk: cmd. line:2: BEGIN rule error--> gawk: cmd. line:2: ^ parse error
`BEGIN' is noted as a syntax error. ここで、バックスラッシュはコメントを次の行に継続しているようにみえる。 どんなやり方でも、バックスラッシュと改行の組み合わせは決して(awkには) 気づかれない。なぜなら、それ(バックスラッシュ)が、コメントの 内部に“隠れた”からである。したがって、`BEGIN'は文法エラーとして指摘 される。
awk
の文があるルールが短いときには、それを一行にいくつもまとめて書
きたいと考えるだろう。そのためにはセミコロン`;'を使って文を区切る。
これはルールそれ自身にも適用できる。したがって、 先の例はこのように書くこともできる。
/12/ { print $0 } ; /21/ { print $0 }
注意: オリジナルのawk
言語では、同じ行にあるルールを
セミコロンで区切らなくても良かった。これ(セミコロンでルールを区切ること)は
アクション中にあるステートメントの扱いとの一貫性をとるために
付け加えられたものである。
awk
のその他の機能。
awk
は、作成したプログラムがawk
から情報を得るための
組込みであらかじめ定義されている幾つかの変数を提供している。
その他にも、プログラム中でawk
がどのようにデータを処理するかを
制御するための変数がある。
さらに、awk
は一般的な計算や文字列操作をおこなうための組込み関数を
提供している。
ここまでawk
について説明してきたように、
我々は変数の大部分と多くの関数を紹介する。これらはセクション 組み込み変数を参照
とセクション 組み込み関数を参照で定義されている。
awk
を使うとき
(セクション より複雑な例を参照.)
あなたは、awk
があなたにとって役に立つのかどうかを疑問に
思うかもしれない。ユーティリティプログラムやパターン、
フィールドの分割、算術文、などの選択基準を使って、
より複雑な出力を作成することができる。
awk
言語はls
のようなほかのユーティリティの出力からの情報を
要約するような、大きな生データからレポートを生成するような作業に便利である。
(セクション より複雑な例を参照.)
awk
で書かれたプログラムは、通常は他の言語で書いたものよりも小さく
なる。これはawk
プログラムの作成と使用を簡単にする。しばしば、
awk
プログラムはターミナルで即座に作成し、一度だけ使って捨ててしま
うということもできる。awk
プログラムはインタープリットされるために、
エディット-コンパイル-デバッグというソフトウェア開発の典型的なサイクル
を避けることができるのである。
完全にretargetableな8ビットマイクロプロセッサ用のアセンブラ(詳しくは
セクション 用語集を参照)や、特殊目的用Prologコンピュータ用のマイクロコ
ードアセン
ブラのような複雑なプログラムがawk
を使って記述されたことがある。し
かしながら、awk
の能力ではこのような複雑な仕事を行うには荷が重い。
2、300行以上のawk
スクリプトを書くようになったとき、違ったプログラミ
ング言語の使用を考えていることに気がつくだろう。 Emacs Lisp は、文字列やパ
ターンマッチングを扱う高度な能力を必要とするときにはよい選択といえる。シェ
ルもまた文字列やパターンマッチングを扱う能力があり、それに加えて強力で便利
なシステムユーティリティを使う事ができる。より伝統的な言語、CやC++、Lispと
いったものは、システムプログラミングや大きなプログラムの複雑さを管理するの
に便利であるだろう。これらの言語で記述したプログラムは、同じ作業をする
awk
プログラムよりも多くの行数を必要とするかも知れないが、より有効に
実行したり、簡単にメンテナンスできる。