GNU AWKはまだまだ成長中! ユーザーの声をもとに作成された拡張機能を組み込んでみよう
► 「シェル芸」に効く GNU AWK処方箋 最終回 (月刊『シェルスクリプトマガジン January 2015(vol.21)』より転載)
GNU AWK(以下、gawk)は標準でGNU MPFR(Multiple Precision Floating-Point Reliably)を用いた拡張があり、数値演算能力が大幅に改善されました。また、個別に拡張機能をロードすることも可能になっており、共有オブジェクトをロードすることにより従来のAWKではできなかった機能を拡張することができます。最終回の今回はこれらのGNU AWKならではの拡張機能について説明していきます。
MPFRによる拡張
GNU AWKをソースからビルドする際、GNU MPFRとGNU MPがすでに導入されている場合には、自動的にMPFR拡張が導入されます。導入されているかどうかは、gawkのバージョンを表示することで分かります。次のように表示されたバージョンは、この拡張が組み込まれています。
$ gawk --version GNU Awk 4.1.60, API: 1.1 (GNU MPFR 3.1.2, GNU MP 5.1.2)
この拡張が組み込まれていない場合には、「(GNU MPFR 3.1.2, GNU MP 5.1.2)」という部分が含まれません。ここでは、この拡張が組み込まれているとして進めていきます。
最も簡単にMPFRによる拡張機能を用いる方法は、gawkの起動オプションで-Mを指定することです。
このMPFRによる拡張機能が組み込まれていないgawkでは53ビットまでの数値を扱えます。これは、次のような例で試すことができます。
$ echo 53 | gawk '{print 2 ^ $1 - 1}'
9007199254740991
$ echo 54 | gawk '{print 2 ^ $1 - 1}'
18014398509481984
2のべき乗は必ず偶数になるため、これから1を引いた数は奇数になるはずですが、2 ^ 54 - 1が偶数になっていることが分かります。これはgawkが53ビット演算までしか正確に計算できていないということです。そこで今度はMPFRを用いた拡張を試してみましょう。
$ echo 54 | gawk -M '{print 2 ^ $1 - 1}'
18014398509481983
検算はbcコマンドで行ってみましょう。
$ echo '2^54-1' | bc 18014398509481983
このように正しく演算を行うことが可能になります。
また同様に、従来のgawkでは非常に小さな数は0として出力されていましたが、MPFRの拡張を用いることで、そのままの数値で扱うことも可能になります。
$ gawk 'BEGIN {x = 1.0e-400; print x + 0}'
0
$ gawk -M 'BEGIN {x = 1.0e-400; print x + 0}'
1e-400
AWKでls
AWKはシェルを介した他のコマンドとの相性が良いため、「シェル芸勉強会」の中でも毎回用いられるコマンドの1つです。しかし、基本的なコマンドほどOS間で出力形式が微妙に異なるため、悩まされたことも多いのではないかと思います。そこで、lsコマンドそのものを作ってみます。
@load "filefuncs"
BEGIN {
passwd = "/etc/passwd";
group = "/etc/group";
FS = ":";
while (getline < passwd > 0) {
user_of[$3] = $1;
}
close(passwd);
while (getline < group > 0) {
group_of[$3] = $1;
}
close(group);
for (i = 1; i <= ARGC - 1; i++) {
stat(ARGV[i], stat_data_of);
m_time = strftime("%Y-%m-%d %H:%M", stat_data_of["mtime"]);
printf("%s %3d %8s %8s %9d %s %s\n",
stat_data_of["pmode"],
stat_data_of["nlink"],
user_of[stat_data_of["uid"]],
group_of[stat_data_of["gid"]],
stat_data_of["size"],
m_time,
stat_data_of["name"]);
}
}
ここで初めて登場した拡張@loadが最初の行にありますが、この@loadにより様々な拡張を行うことができます。ここでは「filefuncs」という拡張を呼び出しています。このfilefuncsによりファイル情報を直接読むことができます。
このfilefuncsではstat()関数が加えられ、このstat()関数の第1引数のファイルの情報が、第2引数の配列に格納されます。また、フォーマットをlsコマンドらしくするため、/etc/passwdファイルと/etc/groupファイルの中身を調べてuidとgidを取得しています。
では、実行してみましょう。
$ touch a b $ gawk -f ls.awk a b -rw-r--r-- 1 hi_saito hi_saito 0 2014-11-03 15:18 a -rw-r--r-- 1 hi_saito hi_saito 0 2014-11-03 15:18 b $ ls -l --time-style=long-iso a b -rw-r--r-- 1 hi_saito hi_saito 0 2014-11-03 15:18 b -rw-r--r-- 1 hi_saito hi_saito 0 2014-11-03 15:18 a
このようにGNUのcoreutilsのlsコマンド(--timestyle=long-isoオプション相当)に近い出力を得ることができました。
本連載が単行本になりました!
この記事は参考になりましたか?
- シェルスクリプトマガジン コラボレーション連載/「シェル芸」に効く GNU AWK処方箋連載記事一覧
-
- GNU AWKはまだまだ成長中! ユーザーの声をもとに作成された拡張機能を組み込んでみよう
- GNU AWKでCSVファイルを楽々あつかう組込変数FPATと、関数のインダイレクト呼び出...
- これは強力! AWKとパイプの新しい関係 ~ 時刻を取得する関数、Socket通信、双方向...
- この記事の著者
-
斉藤 博文(サイトウヒロフミ)
最初にAWKと出会ってから○十年、AWKの魅力に取りつかれ、勢い余って「日本 GNU AWKユーザー会」を立ち上げています。会としてOSCなどのイベントにも出展しつつ、GNU AWKの開発も手伝っています。「USP友の会」では幹事役ですが、「シェル芸勉強会」にはほぼ毎回参加して一緒に勉強しています。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア

