Bash 算术输出结果为十进制

Bash 算术输出结果为十进制

当使用 Bash 进行计算并为其提供十六进制输入时,它可以正确计算,但以十进制形式输出结果。这是正常的吗?显然我想要十六进制的结果,因为我以十六进制给出它们。有办法改变这个吗?

我知道printf,但是printf每次我对带有增量或类似内容的变量进行较小更新时调用,似乎很奇怪。

例如当做

echo $((0xa+1))

结果11却是我预料之中的b

答案1

$((0xa+1))是算术展开式,可展开为算术表达式求值的十进制表示形式0xa+1

0x该表达式后面没有a+1,即0xa(十六进制整数常量)、+二进制加法运算符和1(十进制整数常量)。

据我所知,唯一一个类似 Bourne 的 shell 可以在 10 以外的任何基数中进行整数算术扩展,zsh并且您必须使用以下语法明确指定要扩展的基数:

$ echo $(( [#16] 0xa + 1 ))
16#B
$ echo $(( [##16] 0xa + 1 ))
B
$ set -o c_bases
$ echo $(( [#16] 0xa + 1 ))
0xB

就像在中一样,ksh您可以使用以下方法将基数分配给整数变量:

$ typeset -i16 var
$ (( var = 0xa + 1 ))
$ echo "$var"
16#B
$ set -o c_bases
$ echo "$var"
0xB

(ksh16#b在那里给出,c_bases选项(给出0xBAD而不是16#BAD十六进制,而077不是8#77octal_zeroes选项也设置时)是zsh特定的)。

另外,在 中zsh,如果在整数算术表达式内分配变量(使用=--++*=-=+=等算术运算符),则它会获得整数类型并且(除非已经分配了基数)继承具有显式基数的最右边整数常量的基数(例如10#12, 0x12, 0b11)。

例如,(( a = 0x10 + 0b1000 ))就像typeset -gi2 a=24.定义a为值为 24 的整型变量,并$a以二进制 ( 2#11000) 扩展。

info zsh 'Arithmetic Evaluation'详情请参阅。

bash确实从 ksh复制typeset -i,但不是typeset -i<base>

要将bash数字转换为 10 以外的基数,您可以使用其printf内置函数来表示基数 8 和 16,如其他人所示,或者使用dc/ bc/ ksh/zsh来表示其他基数(支持的基数范围以及它们的表达方式在这些基数之间有所不同) )。

例如,要转换为基数 30:

base30_dc() { echo "30o $1 p" | dc; }
base30_bc() { echo "obase=30; $1" | bc; }
base30_ksh93() { ksh93 -c 'printf "%..30d\n" "$@"' ksh "$@"; }
base30_zsh() { zsh -c 'echo $(([##30] $1))' zsh "$1"; }

其中给出:

$ base30_dc 1234
 01 11 04
$ base30_bc 1234
 01 11 04
$ base30_ksh93 1234
1b4
$ base30_zsh 1234
1B4

但请注意,负数常量用符号dc表示。 _while-是二元减法运算符 (dc使用逆波兰表示法)。

$ base30_dc _1234
- 01 11 04
$ base30_dc '0 1234 -'
- 01 11 04

至于算术表达式内识别的数字类型,在 shell 之间也有所不同。

123POSIX 要求至少分别使用、0123和语法来识别十进制、八进制和十六进制常量0x123。有些 shell 默认情况下喜欢mkshzsh不识别0123八进制,因为这样做会比它有用的时候更频繁地妨碍(例如处理 0 填充的数字时),只有在启用了某些 POSIX 兼容模式时( 、optionposix中的选项或中的仿真)。mkshoctalzeroesshzsh

ksh、bash 和 zsh 支持12#123以任意基数输入数字的表示法(同样,它们之间的范围不同)。

2#111zsh 支持 0b111 作为二进制数的替代。并嵌入_内部数字以帮助易读(例如1_000_0000xdead_beef

ksh93、zsh 和 yash 支持浮点数(0.123(或在 ksh93 中,0,123取决于区域设置)、、、1e20... )。 ksh93 还支持十六进制浮点表示法,如 0xA.Bp-3(或 0xA,Bp-3,具体取决于区域设置)。infnan

答案2

Bash(或者任何其他 shell,实际上)对于一般编程来说并不是一个好的工具。 Bash 甚至不处理浮点运算,更不用说更复杂的运算了。外壳是一个,您可以在其中编写简单的小脚本,但您不应该将其视为一种通用编程语言:它不是。

恐怕如果你坚持使用 bash 来做这样的事情,你将被迫使用越来越复杂的解决方法,从以下开始printf

$ printf '%x\n' "$((0xa+1))"
b

好消息是您至少还可以这样做:

$ printf '%x\n' 11
b

因此,您可以轻松地从一种转换为另一种,这意味着您不需要printf每次都调用:

var=0xa

((var++))
echo "Var (decimal): $var"
printf 'Var (hex): %x\n' "$var"

运行上面的命令会打印:

$ foo.sh
Var (decimal): 11
Var (hex): b

换句话说,您可以以十六进制方式执行操作,而不必关心它的显示方式,直到需要打印出某些内容为止。

但是不,您不会在 shell 中找到执行此类操作的本机方法,因为您试图将 shell 用于其设计目的之外的目的。

相关内容