Awkward Programming in awk
2002-12,
Daichi Mochihashi <daiti-m@is.aist-nara.ac.jp>
0. はじめに
awk とは, テキスト処理用の言語です. 特に, フィールドに分かれたデータの処理に
適しています.
awk のプログラミングについて初心者を対象に解説しているページは結構ありますが,
awk の突っ込んだ知識についてまとめたページは見当たらなかったようなので書いてみました.
awk でのプログラミングについては, 6.
で紹介しておいた入門サイトや
ドキュメントなどをご覧下さい。
1. Why awk?
テキスト処理用の言語としては Perl (最近だと日本では Ruby) などが有名ですが,
どうして awk なのでしょう.
awk には, 次のような利点があると個人的に思っています.
- 変数に
$
や@
がつかない, C言語ライクな簡素な
シンタクス.
- 自動的に分割されるフィールド.
Perl にも自動フィールド分割オプション(-a)がありますが, 個人的な経験としてはあまり使いません.
- ミニマリズム (^^;).
今となっては趣味の範疇ですが, たとえば DOS版 GNU awk 2.15.2 (gawk.exe)
は実行ファイルが約180KBだったのに対し, JPerl 4.036 (jperl.exe) は
約310KBでした.それ以上に違うのがメモリ使用量で, メモリ640KBの MS-DOS
では perl を普段から(特にサブプロセスで)使うのは躊躇されたような記憶が
あります.
この中で, 最も意味があると思われるのはたぶん 1. でしょう.
複雑なプログラムを書くには perl は便利ですが (というか awk では書けない
プログラムも多い), 簡単な処理, 特に最初からフィールドに分かれていることが
わかっているデータを処理するプログラムを書くには awk は便利で, $などがない分
プログラムが見やすくなっています.
また, log, exp, sin, tan-1 などの基本的な算術関数も揃っていますので,
アルゴリズムの簡単な実験にも適しているでしょう.
といっても勿論私も普段から awk を使っているわけではなく (普段使っているのは
Objective Caml と
Perl です), 必要な時に使う程度ですが, 逆に
簡素であるだけに, その可能性を極めるのは面白い言語でもあります.
2. awk の基本書
awk でのプログラミングについて学ぶとき, 最も基本となるのは
でしょう.
この本は awk の文法について深く網羅的に解説してあるだけでなく,
サンプルスクリプトも面白く, 正規表現についての入門もあります.後ろの方では
再帰下降パーサや make の簡単なものを作るなど, アルゴリズムの実験までしていて,
情報科学的に見ても非常に面白いものになっています.
awk の文法は C言語に
似ているので(作者が重なっているので当然ですが), C言語への入門としても適して
いるかもしれません.
なお, 上のベル研究所のAWKのページでは, 原作者が書いた 'One true awk'の
ソースコード(awk.shar, awk.tar.gz) と Windows バイナリ(awk95.exe)が公開されて
います.
その次に有名なのが,
だと思われます.
ただし, この本は awk については一通りの紹介しかしていません.ここで書かれて
いる awk についての内容はほぼ上の「プログラミング言語AWK」に書かれている
ので, この本はどちらかというと awk の本というより, sed の本と言ったほうが
いいでしょう. sed 10行野郎を育成する:) 本は,
仙石さんのSED教室などの
オンライン文書を除けば他にほとんどありません.
この本には後ろに, awk と sed で書かれたいくつかの実用プログラムが載って
いますので, 特にシェルスクリプトとの組み合わせ方などで参考になりそうです.
なお, awk 初心者の方には, (当時)阪大情報処理教育センターの荻原剛志さんの
書かれた「AWKの簡単な使い方」がおすすめです.
私が最初に(自習課題として)先生に渡されて読んだのもこれでした.
付属データは, こちらに置いてあります。
この文書は様々な ftp にアーカイブされていますが,
以前はvectorからもダウンロードすることができました。
3. awk の応用
基本の次は応用です.日本語訳はまだありませんが, O'Reilly から
という本が出ているようです.
本文のXML ソースが, http://examples.oreilly.com/awkprog3/eap3.tar から読めます.
前半は「プログラミング言語AWK」に比べて新しいことはないようですが,
gawk 3.1.x 以降の/inet/
スペシャルファイルを用いた10章の
awk ネットワークプログラミング,
12章のawkライブラリの使い方/作り方(最近の GNU awk には
assert.awk, getopt.awk などいくつかのライブラリが share/awk/ の下に付属
してきます)は最近の拡張として参考になりそうです.
さらに深い awk の知識を目指すなら, 次は
しかないでしょう.:-)
この本はアスキー256倍シリーズらしく, 書き方にちょっと'下品'なところがあって,
上の Addison-Wesley のような瀟洒な本を読んでいると躊躇してしまうかもしれません.
(私は最初引きました.^^;)
が, 実は GNU awk について徹底的に解説し尽くしている本であるのみならず,
gawk の各コマンド/変数の使い方と
簡単なサンプルプログラムのインデックスまで付いていて,
awk でプログラムを書く際のハンドブックとしても, とても重宝する本です.
もちろんその他の内容はマニアの極みで, awk における連想配列がハッシュとして
どのように実現されているか, といった内部構造の解析に始まって, DOS extender
go32版の gawk.exe との速度比較, 果ては awk のソースを書き換えて自分専用の
awk を作る話など, awk をとことん楽しみ尽くしている本です.
巻末には awk で書かれた100行, 200行のプログラムが連続し, これでもかこれでもか
といったawkプログラミングの濃さが味わえます. (^^;)
awk や sed など, コマンドラインで使うスクリプト言語は「1行野郎」と呼ばれ,
1行のプログラムでいかに簡単に仕事を片付けられるか, ということが楽しさでも
ありますが, そういった意味ではこの本は「awk 100行野郎」を養成する本だと
言えます. :-) (中でもそう述べられています.)
なお, この本の「100行awkプログラム」は上のページの
ここから手に入れることができます.
4. awk の極限
単なるテキスト処理言語であるはずの awk ですが, gawk の TeXinfo の
Glossary にもいくつか述べられているように, awk には awk で書かれた
驚くようなプログラムが存在します.
以下で TeXinfo で触れられていないその他のものも含め, これまでに見つけたそうした
極限の awk プログラムをご紹介します.
4.1 awk Assembler
これは gawk の TeXinfo にも載っているものです. gawk.info より:
Amazing `awk' Assembler
Henry Spencer at the University of Toronto wrote a retargetable
assembler completely as `awk' scripts. It is thousands of lines
long, including machine descriptions for several eight-bit
microcomputers. It is a good example of a program that would have
been better written in another language.
このプログラムは
ftp://ftp.freefriends.org/arnold/Awkstuff/aaa.tgz
から入手することができます.
なお, 作者のHenry Spencer氏は
awk で nroff クローン
awf
というものも書いており, 昔は有名なプログラム
だったようです(nroff がインストールされていなくとも, awk さえあれば
man が見れる).awf は, 同じディレクトリの
ftp://ftp.freefriends.org/arnold/Awkstuff/awf.tgzから入手できます.
4.2 awk Lisp interpreter
1994年に alt.sources に, Roger Rohrbach 氏によって awk で書かれた
Lisp インタプリタ walk がポストされました.
(Message-ID: <OZ.94May31112039@ursa.sis.yorku.ca>)
これは探した限りでは,
http://www.funet.fi/pub/archive/alt.sources/volume94/Jun/940601.09.gz
で手に入るようです.
cl:~/atelier/awk/walk% nawk -f walk
walk (LISP in awk) Copyright (c) 1988, 1990 Roger Rohrbach
-> (cons 'a nil)
(a)
-> (set 'l (list 'a 'b 'c 'd))
(a b c d)
-> (car (cdr (cdr l)))
c
-> (set 'S '(lambda (x y) x))
(lambda (x y) x)
-> (set 'K '(lambda (x y z) (x z (y z))))
(lambda (x y z) (x z (y z)))
-> 29 atoms, 140 list cells.
cl:~/atelier/awk/walk%
walk メインドライバ(awk 690行)
walkマニュアル walk.pdf (walk.ms をps->pdf化したもの)
walk のベンチマーク結果が
こちらにあります.
なお, 最近(2001年)になって, Ehud Lamm氏が新しく
Awklisp
というものを書かれたようです.
4.3 その他
- NAIST OBの出雲さんが,
CASL アセンブラを実行/トレースする
casl.awk を公開されています.(何と639行!)
他にも, クロスアセンブラを書かれたりする方は結構
いらっしゃるみたいですね.
- 上の ftp://ftp.freefriends.org/arnold/Awkstuff/ には,
XML parser.awkがありました.
他にも, pic への入力を出力して化学式を書く
chem.gz
など面白いものが色々置いてあります.
- 前に私が awk で簡単な httpd
を書いてみましたが, 海外だと
AWKhttpd
というのがあって有名なようです.他にも
TSGの方が書いたとか聞いたような気がしますので, ま誰でも
考えるってことですね. (^^;)
この中だと, 私は断然 Lisp インタプリタが凄いと思います.アセンブラといえども
(バイナリ文字もテキストに含めれば)結局テキスト処理を行っているといえる
わけですが, これだけは全然意味が違っています.
もちろんスタック等を自力でエミュレートすれば何でもできるわけですが...
5. awk の環境
5.1 各種環境の awk
- Unixでは特に入れない限り awk (&sed, grep)は
普通日本語化されていませんが, マルチバイト文字対応にするパッチは
こちらのページ(Will's trash can)で公開されています.
awk の mb パッチは現在のところ 3.06 に対するパッチが最新のようです
(3.1.0は日本語化されていない).
- Macintosh での awk (jgawk) 環境としては, 山下巌さんの作られた
JGAwk for Macintoshと, そのインタフェース
JGAwk Interfaceが有名です.
- Windows用の gawk/mawk は
vector のこちらにあります.
Macintosh のようなGUI環境で使うものとしては,
河合さん(HCD04102@nifty.com)が
「おーくの友だち」というものをリリースされているようです.
また, Windows では Cygwin を (MacOS Xの場合は Terminalを) 使えば,
Unix と同じように awk が使えます.
- MS-DOSは #! を使えないので, スクリプトを直接実行できるように
するために,
白鷺(鷺)という スクリプトの .com ファイル化ツール, K.Ishino氏作の
#!.com
などを使うことができます.
- X68k版の gawk は
こちら
にあります.
X68k では,
execd
で普通に #!が使えます.
5.2 GNU awk 標準ライブラリ
GNU awk 3.x 以降には,
${prefix}/share/awk/
の下に
以下のようなライブラリが付属しています.
これらを使うには, @include
をプリプロセスする igawk を使って,
#!/usr/local/bin/igawk -f
@include getopt.awk
..
のように書くとよいでしょう.(もちろん, 自力で cpp などに渡しても大丈夫です.
この辺りの話は「AWKを256倍使う本」に色々と書かれていますのでどうぞ.)
- assert.awk
- assert(3) を提供します.
assertion に失敗した場合, エラーは
stderr (特殊ファイル "/dev/stderr") に吐かれます.
- ctime.awk
- ctime(3) を提供します.
- ftrans.awk
- 複数のファイルを入力とするとき, ファイルの最初と最後にある関数を
実行したい場合, これを include して beginfile() と endfile() を定義
することで行えます.
- getopt.awk
- getopt(3) を提供します.
使用例:
while ((opt = getopt(ARGC, ARGV, "ab:cd")) != -1)
printf("opt = %c, optarg = %s\n",
opt, Optarg);
# 終了後, Optind にオプションでない最初のARGVのインデクスがセットされる
for (i = Optind; i < ARGC; i++)
printf("realarg[%d] = %s\n", i, ARGV[i]);
- gettime.awk
- gettimeofday(3) を提供します.
gettimeofday(tm)
とすると, tm["second"],tm["minute"],
tm["hour"],..等で現在の時間が取り出せます.
- group.awk
- libexec/awk/grcat を実行して得た group エントリを基に,
getgrent, getgrnam, getgrgid などを提供します.
- join.awk
s = join(array, 2, 10, "\t");
とすると, 配列arrayの array[2]..array[10]を順にTABで連結した文字列を
返します. join(array, 2, 10, SUBSEP)
とすると何も挟まずに
連結します.
- mktime.awk
- mktime(3) を提供します.
mktime("2002 01 23 12 34 56") は, 1011756896 を返します.
- nextfile.awk
- アクション中で
next;
とすると次の行を読みに行きます
が, これを最初に読んでおくと nextfile(); とすると次の「ファイル」を
読みに行きます. 内部では(簡単ですが), nextfile(); が指定された以降
そのファイルの内容を捨てるアクションが加えられます.
- ord.awk
- perlと同じ ord() と, 文字cをキャラクタコードに換える chr() を提供します.
- passwd.awk
- libexec/awk/pwcat を実行して得た passwd エントリを基に,
getpwent, getpwnam, getpwuid などを提供します.
- round.awk
- round() 関数を提供します (awk にはデフォルトでは floor() も round() も
ない)
6. 関連リンク
7. その他
GNU awk 3.1.0 は extension/ の下にdllを呼んで fork() する
extension("./fork.so", "dlload"); なんてコードがあったり,
/inet/* でネットワークにアクセスできたりと, ほとんど awk の範疇を超えている
ようです. (^^;)
私も(日本語対応していないこともあって)まだ入れていないので,
暇があったら見てみると面白いかなと思っています.
daiti-m@is.aist-nara.ac.jp
Last modified: Sun Oct 2 14:02:15 2022