仅使用 bash 中的内置函数从基数 10 进行任意基数转换

仅使用 bash 中的内置函数从基数 10 进行任意基数转换

我正在尝试整理一个 bash 命令,使用一组指定的字符将数字从 10 基数转换为任意基数(例如,使用字母 az 转换为 26 基数,尽管这实际上不是我的用例)。

以前解决过这个问题,但不是在 bash 中(我的经验有限),而且在相当长的一段时间内都没有解决过。

有任何想法吗?

答案1

我周围有类似的东西,所以我为你润色了一下

#!/bin/bash
#
# usage: convert_base <number-to-convert> <output-base> <output-digit-string>
#
# example:
#   $ convert_base 3735928559 16 "0 1 2 3 4 5 6 7 8 9 A B C D E F"
#   DEADBEEF

decimal_number=$1
output_base=$2
read -ra output_digits <<< "$3"

# TODO various assertions

if ((decimal_number == 0)); then
    output=${output_digits[0]}
else
    while ((decimal_number > 0)); do
        digit=$(( decimal_number % output_base ))
        output="${output_digits[digit]}$output"
        decimal_number=$(( decimal_number / output_base ))
    done
fi

printf '%s\n' "$output"

答案2

基数 2-64 转十进制 - 只需使用内置 BASH$((基数#数字))

> echo $(( 36#B002RD3KCS ))
1117165531505356
> echo $(( 16#FF ))
255

可以使用标准 bc + 辅助函数来完成恢复转换:

# base10 to base2..base52
# Usage: decimal_to_anybase <OtputBase> <DecimalNum>
function decimal_to_anybase()
{
   BASE52=($(echo {0..9} {A..Z} {a..z}));   # array of 'base_digits'
   base="$1";                               # output base 2..52
   arg="$2";                                # source decimal
   res=$(bc <<< "obase=$base; $arg")
   if [ "$base" -le 16 ]; then              # bases 2..16 returned as is 
       echo "$res"
   else                                     # bases 17..52 returned as array indexes
      for i in $res; do 
          echo -n ${BASE52[$(( 10#$i ))]}   # output BASE52[base_digit]
      done && echo
   fi 
}

> decimal_to_anybase 36 1117165531505356
B002RD3KCS

答案3

也许这是显而易见的事实,但 bash 的printf内置函数可以执行基数 8 和 16:

$ printf '%o\n' 1234
2322
$ printf '%#o\n' 1234
02322
$ printf '%x\n' 1234
4d2
$ printf '%#x\n' 1234
0x4d2
$ printf '%X\n' 1234
4D2
$ printf '%#X\n' 1234
0X4D2

甚至十六进制浮点数:

$ LC_ALL=C printf '%a\n' 1234.56
0x9.a51eb851eb851ecp+7
$ LC_ALL=C printf '%A\n' 1234.56
0X9.A51EB851EB851ECP+7

(此处用于LC_ALL=C确保小数基数字符为.

但它不支持您需要更高级 shell(例如 zsh 或 ksh93)的其他基础,也无法手动完成。

要将结果存储在变量中:

printf -v oct %o 1234

比以下方法更有效:

oct=$(printf %o 1234)

在 bash 中(与 ksh93 或某些 BSD 的 sh 相反)意味着分叉一个进程并通过管道发送结果。

对于那些不喜欢 bash 的人,可以在以下位置找到一些其他 shell 的替代品:

相关内容