使用 Bash 进行计算并为其提供十六进制输入时,它会正确执行计算,但会以十进制形式输出结果。这是正常的吗?显然我想要十六进制的结果,因为我以十六进制给出它们。有没有办法改变这种情况?
我知道printf
,但是printf
每次我对带有增量或类似内容的变量进行小幅更新时都调用,这似乎很奇怪。
例如在做
echo $((0xa+1))
Run Code Online (Sandbox Code Playgroud)
结果是11
,但我期望b
。
$((0xa+1))
是算术扩展,扩展为0xa+1
算术表达式求值的十进制表示。
该表达式0x
后面没有a+1
,即0xa
(十六进制整数常量)、+
二元加法运算符和1
(十进制整数常量)。
据我所知,唯一可以在 10 以外的任何基数中具有整数算术扩展产生数的类似 Bourne 的 shell 是zsh
,您必须使用以下语法明确指定您想要扩展的基数:
$ echo $(( [#16] 0xa + 1 ))
16#B
$ echo $(( [##16] 0xa + 1 ))
B
$ set -o c_bases
$ echo $(( [#16] 0xa + 1 ))
0xB
Run Code Online (Sandbox Code Playgroud)
就像在ksh
您可以使用以下命令将基数分配给整数变量时一样:
$ typeset -i16 var
$ (( var = 0xa + 1 ))
$ echo "$var"
16#B
$ set -o c_bases
$ echo "$var"
0xB
Run Code Online (Sandbox Code Playgroud)
(ksh 在16#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
确实typeset -i
从 ksh复制,但不是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"; }
Run Code Online (Sandbox Code Playgroud)
其中给出:
$ base30_dc 1234
01 11 04
$ base30_bc 1234
01 11 04
$ base30_ksh93 1234
1b4
$ base30_zsh 1234
1B4
Run Code Online (Sandbox Code Playgroud)
但是要注意dc
负数常量用_
符号表示。While-
是二元减法运算符(dc
使用反向波兰表示法)。
$ base30_dc _1234
- 01 11 04
$ base30_dc '0 1234 -'
- 01 11 04
Run Code Online (Sandbox Code Playgroud)
至于在算术表达式中识别的数字类型,这也因壳而异。
POSIX需要至少十进制,八和十六进制常数被利用识别出的123
,0123
并0x123
分别语法。默认情况下,某些 shell 喜欢mksh
或zsh
不识别0123
八进制,因为这样做会比有用的更频繁(例如处理 0 填充数字时),仅当启用了某些 POSIX 兼容模式(posix
选项 in mksh
、octalzeroes
选项或sh
中的仿真zsh
)。
ksh、bash 和 zsh 支持12#123
以任意基数输入数字的符号(同样,它们之间的范围不同)。
zsh 支持 0b111 作为2#111
二进制数的替代。并嵌入_
数字内以提高易读性(如1_000_000
或0xdead_beef
)
ksh93的,岩组和佳日支持浮点数(0.123
(或0,123
在ksh93的取决于区域)1e20
,inf
,nan
...)。ksh93 还支持十六进制浮点表示法,如 0xA.Bp-3(或 0xA,Bp-3,具体取决于语言环境)。
Bash(或任何其他 shell,真的)不是一般编程的好工具。Bash 甚至不处理浮点运算,更不用说更复杂的了。shell 是一个shell,您可以在其中编写简单的小脚本,但您不应将其视为一种通用编程语言:它不是。
恐怕如果你坚持使用 bash 做这样的事情,你将被迫使用越来越复杂的解决方法,从printf
:
$ printf '%x\n' "$((0xa+1))"
b
Run Code Online (Sandbox Code Playgroud)
好消息是你至少也可以这样做:
$ printf '%x\n' 11
b
Run Code Online (Sandbox Code Playgroud)
因此,您可以轻松地从一种转换为另一种,这意味着您无需printf
每次都调用:
var=0xa
((var++))
echo "Var (decimal): $var"
printf 'Var (hex): %x\n' "$var"
Run Code Online (Sandbox Code Playgroud)
运行上面的将打印:
$ foo.sh
Var (decimal): 11
Var (hex): b
Run Code Online (Sandbox Code Playgroud)
换句话说,你可以用十六进制做你的事情,而不用关心它是如何显示的,直到你需要打印出来。
但是,不,您不会在 shell 中找到执行此类操作的本机方式,因为您正试图将 shell 用于非设计目的。