当使用 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#77
当octal_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 之间也有所不同。
123
POSIX 要求至少分别使用、0123
和语法来识别十进制、八进制和十六进制常量0x123
。有些 shell 默认情况下喜欢mksh
或zsh
不识别0123
八进制,因为这样做会比它有用的时候更频繁地妨碍(例如处理 0 填充的数字时),只有在启用了某些 POSIX 兼容模式时( 、optionposix
中的选项或中的仿真)。mksh
octalzeroes
sh
zsh
ksh、bash 和 zsh 支持12#123
以任意基数输入数字的表示法(同样,它们之间的范围不同)。
2#111
zsh 支持 0b111 作为二进制数的替代。并嵌入_
内部数字以帮助易读(例如1_000_000
或0xdead_beef
)
ksh93、zsh 和 yash 支持浮点数(0.123
(或在 ksh93 中,0,123
取决于区域设置)、、、1e20
... )。 ksh93 还支持十六进制浮点表示法,如 0xA.Bp-3(或 0xA,Bp-3,具体取决于区域设置)。inf
nan
答案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 用于其设计目的之外的目的。