2013-12-08

算術式(その2) - Bash Advent Calendar - Day 7

昨日の続き、算術式内の変数について。

数値インデックスの配列変数(連想配列じゃない方の配列)にも対応しています。なので
$ declare foo=(1 2 3)
$ declare -i bar="foo[0] + foo[1] + foo[2]"
$ declare -p bar
declare -i bar="6"
これまでと同様、再帰的に算術式として評価されるので
$ declare foo=(0 1)
$ declare bar="foo[0] + foo[1]"
$ declare -i buzz
$ buzz="bar[0] + bar[1]"
$ declare -p buzz
declare -i buzz="3"
これで何が嬉しいのか書いてる本人もよく分かりませんが、とりあえずこんなこともできますよと。

基数#文字列

これで昨日のリストの1〜4を説明しました。6は単純な数値なので、これで最後、今日のメインディッシュ "基数#文字列" です。

これまでに説明した8進数、16進数、そして普段使いの10進数以外に使いそうなのは2進数ぐらいですかね。
$ declare -i foo
$ foo="2#10100101"  # 0xA5
$ declare -p foo
declare -i foo="165"
これまで同様、何が嬉しいのかよくわからないですね。

11進数から36進数までは数字とアルファベット(大文字、小文字の区別なし)で数値を表現します。すなわち
$ declare -i foo
$ foo="36#sekine"
$ declare -p foo
declare -i foo="1717524842"
36進数とか言われても、これで正しいかどうなのかよく分からんですね。せっかくなのでこれまでの算術式やら、配列など色々駆使して、この値を検証してみましょう。
$ char_code_hex=($(echo -n 'asekine' | od -A n -t x1))
$ declare -i -a char_code_hex_num
$ char_code_hex_num=("${char_code_hex[@]/#/0x}")
$ declare -p char_code_num
declare -ai char_code_num='([0]="97" [1]="115" [2]="101" [3]="107" [4]="105" [5]="110" [6]="101")'
とまず、"sekine" と、ついでに "a" の文字コードを取得します。補足として

  • 本当は od で直接 10 進数でダンプできますが、そんなオプション普段使わないよね
  • ${var/pattern/str} で pattern を str に変換しますが、pattern は正規表現ではなく、いわゆる glob パターンで、さらにその拡張版で # は文字列の先頭にマッチします

さて、仕上げで
$ a="char_code_num[0]"
$ c_to_base36="c - a + 10"
$ declare -i sum=0
$ for ((i=1; i < ${#char_code_num[@]}; i++)); do
>   c="char_code_num[i]"
>   let "sum*=36, sum+=c_to_base36"
> done
$ echo $sum
1717524842
ちゃんと一致しましたね。上から順番に説明しておくと
  • 変数 a に "a" の文字コードを(あえて変数展開せずに、いわばその値の入った配列ををさすポインタとして)代入。
  • c_to_base36 は、変数というよりは無名関数の定義、
    • Pythonで言えば lambda : c - a + 10 みたいなもの
    • Scheme なら (lambda () (+ c (- a 10))) みたいな
  • 以下、char_code_numの各要素に対してsum = sum * 36 + c_to_base36() を計算。
a="${char_code_num[0]}" でいいんじゃないかとか、この lambda もどきはなんなんだ、普通に関数定義しろとか色々あるとは思うのですが、全体がネタなので細かいことは気にしないでいきましょう。

ちなみに前日ちゃんと説明しませんでしたが ${#var[@]} で配列変数の要素数を取得できます。残念ながら、配列の各要素の文字数を一気に返してくれたりはしません。

base という単語と数字と言えば、そうみんな大好き Base64 というわけで、明日は簡易 Base 64 デコーダーに挑戦しようかと思います。

0 件のコメント:

prometheusのrate()関数の罠

 久しぶりのAdventカレンダー挑戦、うまくいく気がしません。 閑話休題。実のところ、rate()関数というよりは、サーバー側のmetric初期化問題です。 さて、何らかのサーバーAがあったとして、それが更に他のサーバーBにRPCを送っているとします。サーバーBの方でホワイトボ...