数値インデックスの配列変数(連想配列じゃない方の配列)にも対応しています。なので
$ 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 foo36進数とか言われても、これで正しいかどうなのかよく分からんですね。せっかくなのでこれまでの算術式やら、配列など色々駆使して、この値を検証してみましょう。
$ foo="36#sekine"
$ declare -p foo
declare -i foo="1717524842"
$ char_code_hex=($(echo -n 'asekine' | od -A n -t x1))とまず、"sekine" と、ついでに "a" の文字コードを取得します。補足として
$ 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")'
- 本当は 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 件のコメント:
コメントを投稿