![仅使用 bash 中的内置函数从基数 10 进行任意基数转换](https://linux22.com/image/221823/%E4%BB%85%E4%BD%BF%E7%94%A8%20bash%20%E4%B8%AD%E7%9A%84%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0%E4%BB%8E%E5%9F%BA%E6%95%B0%2010%20%E8%BF%9B%E8%A1%8C%E4%BB%BB%E6%84%8F%E5%9F%BA%E6%95%B0%E8%BD%AC%E6%8D%A2.png)
我正在尝试整理一个 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 的替代品: