Bash 算术输出结果为十进制

con*_*ser 2 bash

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

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

例如在做

echo $((0xa+1))
Run Code Online (Sandbox Code Playgroud)

结果是11,但我期望b

Sté*_*las 8

$((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需要至少十进制,八和十六进制常数被利用识别出的12301230x123分别语法。默认情况下,某些 shell 喜欢mkshzsh不识别0123八进制,因为这样做会比有用的更频繁(例如处理 0 填充数字时),仅当启用了某些 POSIX 兼容模式(posix选项 in mkshoctalzeroes选项或sh中的仿真zsh)。

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

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

ksh93的,岩组和佳日支持浮点数(0.123(或0,123在ksh93的取决于区域)1e20infnan...)。ksh93 还支持十六进制浮点表示法,如 0xA.Bp-3(或 0xA,Bp-3,具体取决于语言环境)。


ter*_*don 6

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 用于非设计目的。

  • @confused_bash_user 不,为什么?试试看:`var=0xa; var=$((var+1)); var=$((var+0xc)); printf 'Var (hex): %x\n' "$var"`。这将打印“17”,即十六进制的“23”。这不是你想要的吗?关键是`$var` 包含一个数字。您选择如何表示该数字取决于您,它不会影响变量的值。 (2认同)