たぶんまだまだ初級な小ネタ。
こんな感じに16進数(プレフィックスなし)のデータが並んでいるテキストファイルtest.datがあって:
00000000 00000001 0000000F 00000010 7FFFFFFF 80000000 FFFFFFFE FFFFFFFF
これを元データ(32bit符号なし整数)としてちょっとした分析をしたかった(本来のデータは、もっと件数が多く、値もバラエティに富んでいる。ただし数値としてソート済みなのは同じ)。
したかったのだが、awk(1)とか、デフォルトで16進数を扱えなかった。恥かしながら、初めて気づいた……。
そこでbc(1)を使って10進数に変換してみた。
$ echo ibase = 16 | cat - test.dat ibase = 16 00000000 00000001 0000000F 00000010 7FFFFFFF 80000000 FFFFFFFE FFFFFFFF $ echo ibase = 16 | cat - test.dat | bc 0 1 15 16 2147483647 2147483648 4294967294 4294967295 $ echo ibase = 16 | cat - test.dat | bc >test_dec.dat $ _
これで、他のツールで扱いやすくなった。
bc(1)を使う手法は、テキスト処理で「力任せな計算式」を組み立ててしまえばよい、という点で、少々興味深い。
$ # 取り扱うデータはこんな感じ。 $ cat test_dec.dat 0 1 15 16 2147483647 2147483648 4294967294 4294967295 $ # 各データについて、2で割った値を求める(小数第二位まで表示) $ sed '1s/^/scale = 2; /;s!$! / 2!' test_dec.dat scale = 2; 0 / 2 1 / 2 15 / 2 16 / 2 2147483647 / 2 2147483648 / 2 4294967294 / 2 4294967295 / 2 $ sed '1s/^/scale = 2; /;s!$! / 2!' test_dec.dat | bc 0 .50 7.50 8.00 1073741823.50 1073741824.00 2147483647.00 2147483647.50 $ # 最初のデータを捨てる。 $ # 3番目以降のデータについて、2番目のデータとの差分を求める。 $ sed '1d;2s/^/n = /;3,$s/$/ - n/' test_dec.dat n = 1 15 - n 16 - n 2147483647 - n 2147483648 - n 4294967294 - n 4294967295 - n $ sed '1d;2s/^/n = /;3,$s/$/ - n/' test_dec.dat | bc 14 15 2147483646 2147483647 4294967293 4294967294 $ # 1つ前のデータとの差分を求める。 $ sed '1s/^/n = /;2,$s/^.*$/& - n; n = &/' test_dec.dat n = 0 1 - n; n = 1 15 - n; n = 15 16 - n; n = 16 2147483647 - n; n = 2147483647 2147483648 - n; n = 2147483648 4294967294 - n; n = 4294967294 4294967295 - n; n = 4294967295 $ sed '1s/^/n = /;2,$s/^.*$/& - n; n = &/' test_dec.dat | bc 1 14 1 2147483631 1 2147483646 1 $ _
まあ、不正なデータが入力されない(処理するデータはエラーチェック済みで、不正値は取り除かれている)という前提があるからこそ可能な手法ではある。本質的にはサーバサイドのXSSと同じ危険性があるからなあ。