Bash 的算术运算
Bash 的算术运算
可通过declare -i
声明整数变量,具体请看《Bash 变量》的declare 命令
小节
算术表达式
((...))
语法可以进行整数的算术运算。((...))
会自动忽略内部的空格,所以下面的写法都正确,得到同样的结果。不过算术表达式只能计算整数,否则会报错。
|
|
|
|
只能计算整数,不能计算小数
|
|
算数表达式不返回值,表达式地执行的结果根据算术运算的结果而定。只要算术结果不是0
,表达式就算执行成功,即$?
为 0。如果表达式结果为0
,则表示执行失败,$?
就不为0
,一般都会为1
|
|
如果要读取算术运算的结果,需要在((...))
前面加上美元符号$((...))
,使其变成算术表达式,返回算术运算的值。
我们在《Bash 的模式拓展》中的
算术扩展
小节已经接触过
|
|
((...))
语法支持的算术运算符如下。
+
:加法-
:减法*
:乘法/
:除法(整除):除法运算符的返回结果总是整数,比如5
除以2
,得到的结果是2
,而不是2.5
%
:余数:比如5
除以2
,余数是1
**
:指数++
:自增运算(前缀或后缀):++i
表示先加后用,i++
表示先用后加--
:自减运算(前缀或后缀):与上同理
((...))
内部还支持()
的嵌套,就像写数学表达式一样,$((...))
结构可以嵌套。
|
|
自增
|
|
$((...))
的圆括号之中,不需要在变量名之前加上$
,不过加上也不报错。
如果在$((...))
里面使用带引号的字符串,会报错,
在大佬的博客中,
$((...))
会将带引号的字符串认作是一个变量名。跟我的实际情况不一样。
|
|
如果$((...))
里面使用不存在的变量,或者变量的值不为整数,也会当作0
处理。
|
|
如果变量的值为整数,则会生效
|
|
最后,$[...]
是以前的语法,也可以做整数运算,不建议使用。
|
|
数值的进制
Bash 的数值默认都是十进制,但是在算术表达式中,也可以使用其他进制。
number
:没有任何特殊表示法的数字是十进制数(以 10 为底)。0number
:八进制数。0xnumber
:十六进制数。base#number
:base
进制的数。
不同进制的数,在算数表达式中可以进行运算,最终通过 echo 输出的时候的时候,都会转化为十进制数,非常方便。
简单实践:
|
|
位运算
$((...))
支持以下的二进制位运算符。
<<
:位左移运算,把一个数字的所有位向左移动指定的位。>>
:位右移运算,把一个数字的所有位向右移动指定的位。&
:位的“与”运算,对两个数字的所有位执行一个AND
操作。|
:位的“或”运算,对两个数字的所有位执行一个OR
操作。~
:位的“否”运算,对一个数字的所有位取反。^
:位的异或运算(exclusive or),对两个数字的所有位执行一个异或操作。
下面是二进制数位运算的的例子。
|
|
这里解释一下为什么$((~2#1100))
为-13
,这里涉及到计算机中二进制存储相关的知识,在计算机中所有的数字都是以二进制补码的形式进行存储和表示的,也是以补码的方式进行计算,那2#1100
也是补码,按位取反之后就是2#0011
,这就是补码,那这个补码对应的二进制数怎么求呢?先计算其反码0010
,然后获取原码1101
,然后就是 13,然后因为之前符号位是 0,现在符号位取反,就是 1,所以为负数,就是 -13,所以最后输出 -13
关于原码、反码、补码的知识,请看《Java 核心技术卷一_第 3 章_Java 基本程序设计结构》的
原码、反码、补码
小节。
也可以对十进制数进行位运算,不过看起来就不明显了
|
|
7 的补码和源码相同,是111
逻辑运算
$((...))
支持以下的逻辑运算符。
<
:小于>
:大于<=
:小于或相等>=
:大于或相等==
:相等!=
:不相等&&
:逻辑与||
:逻辑或!
:逻辑否expr1?expr2:expr3
:三元条件运算符。若表达式expr1
的计算结果为非零值(算术真),则执行表达式expr2
,否则执行表达式expr3
。
如果逻辑表达式为真,返回1
,否则返回0
。
我们在《Bash 条件判断》小节中会使用
test
命令进行条件判断,但是写起来比较麻烦,比如-gt
、-lt
,如果是简单的算数运算的话,直接使用算数表达式直接使用>
或者<
会比较方便。
简单实践:
|
|
上面例子中,第一个表达式为真时,返回第二个表达式的值,否则返回第三个表达式的值。
赋值运算
算术表达式$((...))
可以执行赋值运算。
|
|
上面例子中,a=3
对变量a
进行赋值。这个式子本身也是一个表达式,返回值就是等号右边的值。
$((...))
支持的赋值运算符,有以下这些。
parameter = value
:简单赋值。parameter += value
:等价于parameter = parameter + value
。parameter -= value
:等价于parameter = parameter – value
。parameter *= value
:等价于parameter = parameter * value
。parameter /= value
:等价于parameter = parameter / value
。parameter %= value
:等价于parameter = parameter % value
。parameter <<= value
:等价于parameter = parameter << value
。parameter >>= value
:等价于parameter = parameter >> value
。parameter &= value
:等价于parameter = parameter & value
。parameter |= value
:等价于parameter = parameter | value
。parameter ^= value
:等价于parameter = parameter ^ value
。
基本上就是支持算术运算和位运算的赋值运算,使用起来还是很方便的
|
|
如果在表达式内部赋值,可以放在圆括号中,否则会报错。
|
|
求值运算
逗号,
在$((...))
内部是求值运算符,执行前后两个表达式,并返回后一个表达式的值。也就是说,通过在$((...))
中使用,
,可以将多个表达式写在一个$((...))
内部,并返回最终的计算结果
|
|
expr 命令
expr
命令支持算术运算,可以不使用((...))
语法。注意符号跟数字之间必须有空格,否则会当成字符串直接输出
总体来说,使用体验不如算数运算符
|
|
expr
命令支持变量替换。
|
|
expr
命令也不支持非整数参数。
|
|
上面例子中,如果有非整数的运算,expr
命令就报错了。
let 命令
let
命令用于将算术运算的结果,赋予一个变量。
|
|
上面例子中,变量x
等于2+3
的运算结果。
注意,x=2+3
这个式子里面不能有空格,否则会报错。
let
命令的详细用法参见《Bash 变量》。