在bash中进行基本数值计算
由于bash
是一种解释性语言,所以在bash
中,默认情况下,只会进行字符串的运算,比如:
bash
x=3+2
echo ${x}
上述代码的结果不是5
,而是字符串3+2
。这是bash
的特性,要进行数值运算,必须使用shell
扩展或者内置命令。
如何在bash
中计算数值运算
在bash
中,提供了3种方法来计算数值运算,分别是:
- 使用
(())
复合命令 - 使用
let
内置命令 - 使用
declare
内置命令
使用复合命令进行数值计算
使用(())
复合命令进行数值计算,在bash
使用中是使用最多的,最普遍的,只需要将要计算的式子放入到(())
复合命令中即可,比如上述的代码可以修改为如下:
bash
x=$((3+2))
echo ${x}
在进行复合命令的时候,没有语法要求,直接将表达式写入复合命令中即可,不需要刻意在计算符号留空格。
上述代码的输出结果就是5
,不过要注意的是,复合命令需要搭配$
符号来使用,式子中可以直接引用变量,而无需进行变量替换,比如:
bash
x=2
y=3
z=$((x+y))
echo ${z}
a=$((${x}+${y}))
echo ${a}
在上述代码中,虽然z
和a
的最后的值都是5
,但是这2个式子其实是有区别的,z
计算的是x
和y
变量的值,而a
计算的是x
和y
引用数值值,实际上是在计算2
和3
的值。
使用内置命令let
进行数值计算
除了使用(())
内置命令计算数值以外,还允许使用内置命令let
来进行数值运算,使用过程也非常简单,只需要在计算变量之前使用let
关键字即可,比如同样计算上述的2+3
,案例如下:
bash
x=2
y=3
let z=x+y
echo ${z}
此时z
的值当然是5
,使用let
进行计算的时候,需要注意,数字和表达式之间不能有空格,比如:
bash
let z=x + y
这个是有问题的,当bash
在执行到空格的时候会报错,此时会将将错误抛出来,而将x
的值返回给z
。
比如案例如下:
bash
x=2
y=3
let z=x + y
echo ${z}
执行结果为
bash
# bash a.sh
a.sh: line 6: let: +: arithmetic syntax error: operand expected (error token is "+")
2
#
上述所述,z
的值将会为2
,而报错将会通过stderr
输出输出,不会影响程序后续执行。
但是在bash
中,使用let
计算的时候,如有空格,可以使用括号括起来,比如:
bash
let z='x + y'
此时,z
的结果将会为5
,空格不能影响其结果。
使用内置命令declare
进行数值计算
使用declare
中的-i
参数,可以将变量给声明为int
类型,而后进行数值运算的时候,解释器会进行数值运算,而非进行字符串运算,比如同样的3+2
,使用declare
,可以将其写为:
bash
x=2
y=3
declare -i z
z='x + y'
echo ${z}
上述例子中,将z
给声明为了int
类型的变量,而在进行x+y
的时候,会进行数值运算,从而得到结果为5
,这里需要注意,如果表达式有空格,必须使用引号将式子括起来。
如果不括起来的话,则会报错,且待计算变量的值为初值,比如:
bash
declare -i z
z=x + y
假设已经提前定义好了x
和y
的值,当计算z=x + y
的时候,由于表达式有空格,所以会报错,且z
的值为初值,即空值,这是和let
计算不一样的地方。
bash运算操作符
普通运算符
在bash
中,提供了如下运算法:
- 加法、减法:
+
、-
- 乘法、除法:
*
、/
- 取余:
%
- 幂运算:
**
这些都比较基础,可以通过下面案例说明:
bash
declare -i x=0
x=x+7
echo x+1: ${x}
x=x-2
echo x-2: ${x}
x=x/3
echo x/3: ${x}
x=x*5
echo x*5: ${x}
x=x%3
echo x%3: ${x}
x=x**3
echo x**x: ${x}
上述例子中,首先声明了x
为整形,而后分别计算:
x+7
、x-2
、x/3
、x*5
、x%3
、x**3
这些表达式的结果,其中第一个表达式的结果,将作为第二个表达式x
变量的值来使用,其次类推。
最后运行的值为:
bash
# bash a.sh
x+1: 7
x-2: 5
x/3: 1
x*5: 5
x%3: 2
x**x: 8
#
通过简单的运算,可以发现上面的结果都符合预期。
比较运算
在bash
中还支持比较运算,其运算符为:
<
:小于>
:大于<=
:小于等于>=
:大于等于==
:判断相等!=
:判断不等
首先,在bash
中,是没有bool
类型的,而是利用返回值进行判断,当为true
的时候,返回0
,当为false
的时候,将会返回非0
数字。
在传统shell
中,判断相等使用test
表达式,搭配-eq
来使用,而使用$?
来获取命令的返回值,比如:
bash
# test 3 -eq 2
# echo $?
1
#
上面例子判断3
是否和2
相等,再获取其返回值,返回值为1
可以理解为返回false
。
bash
# test 3 -eq 3
# echo $?
0
#
而当判断3
是否和3
相等的时候,返回的是0
,则可以理解为true
。
在bash
中,注意,这个是bash
的特性,可以直接使用熟知的比较运算符了,比如>
、<
等等,不过需要搭配bash
特定的(())
语法使用。
基于如上所述,可以搭配(())
语法,可以写一些比较完整的例子。
大于、小于、大于等于、小于等于案例脚本:
bash
#!/bin/bash
declare -i x=$1
declare -i y=$2
echo x:${x} y:${y}
# 大于和小于
if ((x > y));then
echo 'x > y'
else
echo 'x < y'
fi
# 大于等于 和 小于等于
if (( x>=y ));then
echo 'x >= y'
fi
if (( x<=y ));then
echo 'x <= y'
fi
# 相等和不相等
if (( x==y ));then
echo 'x == y'
fi
if (( x!=y ));then
echo 'x != y'
fi
上述脚本,从命令行去第一个参数赋值给x
、取第一个参数赋值给y
,然后进行x
和y
的大小判断,若x
大于y
,则输出x > y
,反正则输出x < y
。大于和小于也是一样的。
分别测试3组数据,结果如下:
bash
# bash a.sh 1 3
x:1 y:3
x < y
x <= y
x != y
# bash a.sh 3 1
x:3 y:1
x > y
x >= y
x != y
# bash a.sh 1 1
x:1 y:1
x < y
x >= y
x <= y
x == y
#
上述测试了3组例子,结合传入的参数来看,是能够达到预期的。
自增、自减
在bash
中,可以使用x++
、x--
、++x
和--x
相关运算符的,但是它只会计算结果,不会将值叠加到自身变量中,还是需要赋值的形式才行。
比如有如下代码:
bash
declare -i x
++x
这种语法是错误的,++x
并不会自行迭代增加,而是一个表达式,需要写入到一个变量中,比如:
bash
declare -i x
x=++x
这样才会一个完整的表达式,其该x
的值将会是1
。
前自增 和 后自增的区别,可以写一个案例说明,如有以下代码:
bash
#!/bin/bash
declare -i x=1
declare -i y
y=x++
echo x: ${x}
echo y: ${y}
如上代码表示后自增,该代码的含义为,现将x
的值赋值给y
,然后实现自身变量+1
,所以上述结果应该是y
为1
,而x
为2
。
bash
# bash a.sh
x: 2
y: 1
#
如果是前自增,则会先使变量的值+1
,然后再赋值给其他变量,比如,有如下代码:
bash
#!/bin/bash
declare -i x=1
declare -i y
y=++x
echo x: ${x}
echo y: ${y}
如上代码,x
和y
的结果,都应该为2
,因为x
首先进行自增1
,然后再赋值给y
。
前自减,后自减也是类似的原理,比如有如下代码片段:
bash
declare -i x=2
declare -i y
y=--x
最后的结果是x
和y
的值,都将为1
,这是因为在进行--x
运算中,先进行x-1
,赋值给x
,然后再赋值给y
,所以说,y
的结果也是1
。
而对于后自减,则先进行赋值,而后在减1
,比如有如下代码片段:
bash
declare -i x=2
declare -i y
y=x--
上述代码,y
的值为2
,而x
的值为1
。
总结
在bash
中,有3种方式可以进行数值运算,分别是使用(())
复合命令,使用内置命令let
,以及将变量声明为整形的declare -i
命令,其中除了(())
在计算中,允许变量之间出现空格,其余2种都不能有空格,否则会计算失败,不同的是let
计算失败会取用中间值,而declare -i
定义的变量计算失败,则会为初值。
在bash
中进行数值运算的时候,需要将其转换为整形才行,否则默认会进行字符串匹配运算,而在进行比较运算的时候,可以使用bash
特性,将表达式包含在(())
进行计算。
此前写过关于sh
对于数值的判断,相对于bash
而言,在bash
中进行数值判断,有一丢丢高级语言的味道了。