gawk で strtonum を使うときの注意
たまに csv を処理するのに csv オプションのために gawk を使っているんですが、ちょっと困惑したことがあったので覚書として残しておきます。
はじめに
NAME,SCORE
Adam,0x11
Brian,100
Charlie,0
David,Emmie
このようなファイルからヘッダーと SCORE が数字以外になっている行を除いたものがほしいとする。
単純に、
$2 ~ /^[0-9]+$/ {print $0}
# Brian,100
# Charlie,0
というのが第一に思いつくところではないか。
しかし、負の数や 16 進数があるとうまくいかない。
ここで思いつくのが strtonum だ。gawk 拡張だが、前述の通りここでは gawk を前提とする。
strtonum
strtonum は読んで字のごとく文字列を数字にしてくれる便利関数である。
これを私は次のように使ったことがある(この記事はそのときに調べたことの要約である)
# post.txt は上記の test.csv とはなんの関係もない。
sed -n '2,$p' posts.txt | \
gawk --csv 'strtonum($3) {print $0}' |
sort -k 3 -t , -n | \
# 以下略
このスクリプトの気の利いていない点は sed が不要なこともあるが、 $3 が 0 のときも無視されてしまうことが問題だ。
具体的は下のコードのようになる。
{
if (strtonum($2)) {
print $1,strtonum($2)
} else {
print $1,$2, ": An error occurred."
}
}
# NAME SCORE : An error occurred.
# Adam 17
# Brian 100
# Charlie 0 : An error occurred.
# David Emmie : An error occurred.
これは awk では 0 を偽として扱うということであるから、次のようにする。
$ cat test.csv | gawk --csv '(strtonum($2) || $2 == "0") {print $1,strtonum($2)} '
# Adam 17
# Brian 100
# Charlie 0
他の awk で strtonum を使いたい場合は Link から GNU Awk のマニュアルにコードがあるのでそちらを参照されたい。
おわりに
結局の所 awk では 0 は falsy であるということだ。
falsy のポリシーは言語ごとに異なっているため気をつけよう。