👏

プログラミング言語AWKのここがLOVE

2024/08/25に公開

プログラミング言語AWKが好きなので、この言語のどこが好きかを語ります。主にAWKを知らない、知ってるけど使ったことが無いかた向けの記事ですが、使ったことがあるかたも「こういう思いで使ってる人がいるのか」と遠巻きに眺めてもらえればと考えます。また、後半で最近出たAWKの書籍についても紹介しているので、そちらも役立つかもしれません。

AWKとは

AWKは1977年にAT&Tベル研究所で生まれたプログラミング言語です。AT&Tベル研究所といえばUNIXが生まれたところです。著者もUNIXに縁が深い、この世界のレジェンドばかりです。たとえばKernighan先生はプログラミング言語Cをはじめ、たくさんの書籍の著者として有名です。なんだか強そうな言語ではないかという気がしてきました。

AWKは汎用プログラミング言語ですが、「1行1レコードになっているテキストファイルを最小の手間で処理するワンライナーを書く」ことが非常に得意です。大昔に生まれたこと、および、現在ではPythonやRubyをはじめ、その手のことを得意とする言語が今はたくさんあるので使ったことが無い人、あるいは存在を知らない人もいるでしょう。誕生から今まで劇的な言語仕様の変化が無かったこともあって、ソースの見た目もちょっと古臭いです。しかし、前述のような現代的な言語をある程度使える私でも、今でもあえてAWKを使う場面が多々あります。なぜそうなのか、何がLOVEなのかを紹介していきます。

AWKの使い方

前置きが長くなりましたが、ここからAWKの書き方の紹介をします。入力は「CPUベンダ名」と「プロセッサ名」という2つのフィールドをタブで区切った1行から成るレコードが複数並んでいるテキストファイル、input.txtです。

amd	ryzen
intel	pentium
amd	athlon
transmeta	crusoe
intel	core
amd	opteron
amd	epyc

各行の第1フィールドを表示する場合は以下のように書きます。$1が第1フィールドをあらわします。

$ awk '{print $1}' input.txt
amd
intel
amd
transmeta
intel
amd
amd

第2フィールドを表示する場合は$1$2に変更します。

$ awk '{print $2}' input.txt
ryzen
pentium
athlon
crusoe
core
opteron
epyc

かなり少ない打鍵数で実現できました。これはワンライナーを書くときに大きなアドバンテージとなります。じつはこの程度であればcutコマンドで以下のように第1フィールドを出力するようなことができます。

$ cut -f 1 input.txt
amd
intel
amd
transmeta
intel
amd
amd

ただし、もう少し複雑になるとcutではできないことが出てきます。以下はCPUベンダがamdであるプロセッサ名の数を数えるコードです。AWKでは各行に適用する{}の中のコードを実行する条件を{}の左側に書けます。

$ awk '$1=="amd"{n+=1}END{print n}' input.txt
4

このように「特定のフィールドを取り出すだけではなく、もうちょっと複雑なことをする」のにAWKは向いています。

なんでわざわざAWKを使うのか

ではここで当然出てくるであろう「それ他のスクリプト言語でもできるよ」という疑問について私の見解を示します。このあたりはかなり個人の好みによるところなので、他人に思いを強制するつもりはありません。

例として、input.txtの第2フィールドを表示するワンライナーをRubyで書くとします。ここではRubyを比較対象として選びましたが、「サクッとテキスト処理をするのが得意」とされている言語ならなんでもいいです。話をもとにもどすと上記のようなことをするワンライナーは次のようになります。

$ ruby -e 'ARGF.each do |l| puts l.chomp().split("\t")[1] end' input.txt
ryzen
pentium
athlon
crusoe
core
opteron
epyc

はい。当然書けます。ただし私の感覚では「ソースコードに書くものならいいけどワンライナーでこれはちょっと打鍵数が多くて大変だな」と思います。AWKだと10文字だったものがRubyだと50文字になります。

とか言った直後に何ですが、Rubyは以下のコマンドラインオプションを使うとAWKっぽく書けます。

  • -n: 一行ごとに-eの後の指揮を評価する。
  • -a: 毎行、行の内容をいいかんじに分割して$Fに保存する。

これらのオプションを使うと以下のように書けます。

$ ruby -nae 'puts $F[1]' input.txt
ryzen
pentium
athlon
crusoe
core
opteron
epyc

Rubyすごい。でも-naeの打鍵がめんどくさいので、私はここでRubyを使いません。まあこれは大した違いはないので単に好みの問題によるところが強いです。ただし「CPUベンダがamdであるプロセッサ名の数を数えるコード」だとこうはいかず、ワンライナーで書こうとはまず思いません。

わたしがAWKを使わない場面

「AWKとは」の節で書いた通り、AWKは汎用プログラミング言語です。しかし、やろうとおもえばかなりのことができます。しかし、以下のようにある程度複雑なことをしようとすると、RubyなりPythonなり他の言語で真面目にコードを書くほうが楽になってくると思っています。

  • 1行1レコードになっていない: getline()という関数を使えばある程度処理できますが、限界があります。
  • レコードの構造が複雑: たとえばJSONやYAMLのパース機能はないです。
  • レコードを処理するコードが複雑。具体的には2,3文では終わらない。

一応書いておくと、AWKはワンライナーを書くだけでなく、ソースをファイルに保存してawk -f <ソースファイル>という形式で読み出すこともできます。

このように、私は以下のような場合にAWKを使います。

  • 1行1レコードが続くようなファイルを処理したい
  • cutのような単機能を提供するコマンドでは力不足
  • 各行に適用する処理がある程度単純で、ワンライナーで書ける

それなりに用途が限定されますが、このようなケースは日常的にあります。もちろんこのような判断をするのが面倒なので最初からスクリプト言語を使うという選択肢も全然ありだと思います。ただ、私はそうしない、上記のようなケースではAWKを使う、というだけです。

余談ですがAWKでDOOMのような3Dシューティングゲームの簡易版、awk-raycasterというゲームがあります。これはAWKでできることがかなりあることを示すいい例だと思います。ただ真面目にこういうのを作りたい場合はAWK以外で書くほうが遥かに楽だと思います。このゲームの作者がなぜこれを作ろうと思ったのかは定かではないですが、わたしはこういうのは大好物です。

書籍の紹介

プログラミング言語AWK 第二版というAWKの作者達自身が書いた本が2024年に出版されました(原著は2023年出版)。本書はAWKを学ぶのにとても良い本なので、紹介しておきます。

本書のコンテンツは以下のようなものです。

  • 基本的な文法の解説
  • 簡単な処理をするプログラムの作成
  • ある程度本格的なプログラムの作成
  • リファレンス

ある程度本格的なプログラムのところはなかなか硬派なコンテンツ揃いで面白かったです。「AWKでこんなことをするのは考えたことなかったな」と新鮮な思いで見られました。ただ面白くみられるのはそれとして、やっぱり私はAWKで難しいことをすることは今後ないだろうなとも思いました。

個人的には紙のリファレンスが一番ありがたかったです。言語仕様が小さいので数十ページ程度しかないのも嬉しいです。はるか昔に第一版が出たとき(英語版は1988年、日本語版は1989年に出版された)から追加されたUnicodeとCSVのサポートも紹介されています。どちらもAWKという言語の特性上、よい拡張だと思います。

後書きには本言語を設計した意図、どんな意図でどのように拡張されてきたかが書かれています。この後書きは読んでいて楽しいとともに、歴史的価値があるとも思いました。

おわりに

私のAWKへの愛は語り終えました。AWKは使い方を間違えなければとてもよい言語です。興味が出たかたは一度試してみると良いと思います。とはいえ無ければどうしようもないというものでもないので、本記事を読んでまったく刺さらなかったが無理して学ぶほどのものでもないです。好きにすればいいと思います。

以上。

Discussion