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

Getting Started with awk

awkの基本的な機能は、ファイルからあるパターンを含んでいる行(もし くは他のテキストの構成単位)を検索することである。ある行がパターンの一つ にマッチしたとき、awkは特定のアクションをその行に対して実行する。 awkはこのようにして入力ファイルの最後の行までそれぞれの行を処理し 続ける。

awkのプログラムは他の大部分の言語とは異なっていて、data-driven である。これは処理したいと思うデータについて記述し、さらにそれを 見つけたときにどのようなことをするのかということについて記述する。という ことである。他のほとんどの言語は手続き型(procedural)である。それら においては、事細かに、プログラムの各ステップ毎にどのようにするかを記述し なければならない。手続き型言語を使用しているときは、あなたがプログラムで 処理しようとしているデータがどのような構造をしているかを明確に記述するこ とは、一般的には簡単ではない。このため、awkプログラムはしばしば書 くのも、読むのもやさしいということになるのである。

awk を実行したときにawk がどのように動作するかをawk プログラムで指定できる。プログラムはルールの集まりからなる(関数定義も含ま れるが、高度な機能なので今のところは無視する。 セクション ユーザー定義関数を参照.)。 個々のルールはある特定のパターンを探し、見つかったパターンで定義されたア クションを実行する。

文法的には、ルールはパターンとそれに続くアクションから構成される。アクショ ンはカーリーブレースによってアクションと区切られる。ルールは一般的には改行 によって区切られる。その結果、 awk プログラムは以下のような形式と なる。

pattern { action }
pattern { action }
...

A Rose By Any Other Name

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'

このとき、awkprogramの入力を標準入力にする。 標準入力は通常、あなたが端末からタイプしたものである。 これはあなたが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 プログラムよりも多くの行数を必要とするかも知れないが、より有効に 実行したり、簡単にメンテナンスできる。


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