Bashだけで10進数からn進数(2~64進数)に変換する


はじめに

10進数からn進数(2~64進数)に変換するBashスクリプトの関数です。今回は引数チェックも入れました。Bash 4.4.12で動作を確認しています。
参考記事→Bashだけで16進数・10進数・2進数間の相互変換を行う

コード

conv_digit.sh
# Usage: conv_digit 17 2 # -> 10001
# Usage: conv_digit 31 16 # -> 1f
function conv_digit()
{
  local natural digit quotient surplus sign c64 result
  c64='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@_'
  [[ ! $1 ]] && return
  if [[ ! $1 =~ ^[+\-]?[0-9]+$ ]]
  then
    echo "${FUNCNAME[0]}($1,$2): Arg 1 is invalid. call from ${FUNCNAME[1]}():${BASH_LINENO[0]}">&2
    return -1
  fi
  [[ $1 -lt 0 ]] && { natural=-$1;sign=-; } || natural=$1
  if [[ $2 ]]
  then
    if [[ ! $2 =~ ^[0-9]+$ || $2 -lt 2 || $2 -gt 64 ]]
    then
      echo "${FUNCNAME[0]}($1,$2): Arg 2 is invalid. call from ${FUNCNAME[1]}():${BASH_LINENO[0]}">&2
      return -1
    else
      digit=$2
    fi
  else
    digit=10
  fi
  echo -n $sign
  while :
  do
    surplus=$(($natural%$digit))
    natural=$(($natural/$digit))
    result=${c64:$surplus:1}$result
    [[ $natural -eq 0 ]] && break
  done
  echo $result
}

使い方

$ conv_digit 17 2
10001
$ conv_digit 31 16
1f
$ conv_digit 31
31

n進数から10進数にするにはBashの組み込み機能で行なえます。

$ echo $((16#1f))
31
$ echo $((16#$(conv_digit 31 16)))
31

補足

第一引数は変換する10進数自然数のつもりでしたが、先頭に0がつく数字は8進数として、先頭にマイナス記号(-)がつく数字は負の数として認識されるようですが、完全には動作を確認していません。小数は扱えません。
なお第二引数は進数を指定します。2から64の整数のみを指定でき、負の値や小数はエラーになります。指定しない場合は10として扱われます。

諸注意

コードはご自由に使って頂いて構いませんが、一切の保証はいたしません。