在bash中进行基本数值计算

在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}

在上述代码中,虽然za的最后的值都是5,但是这2个式子其实是有区别的,z计算的是xy变量的值,而a计算的是xy引用数值值,实际上是在计算23的值。

使用内置命令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

假设已经提前定义好了xy的值,当计算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+7x-2x/3x*5x%3x**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,然后进行xy的大小判断,若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,所以上述结果应该是y1,而x2

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}

如上代码,xy的结果,都应该为2,因为x首先进行自增1,然后再赋值给y

前自减,后自减也是类似的原理,比如有如下代码片段:

bash 复制代码
declare -i x=2
declare -i y

y=--x

最后的结果是xy的值,都将为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中进行数值判断,有一丢丢高级语言的味道了。

相关推荐
dingdingfish3 天前
GNU Parallel 学习 - 第1章:How to read this book
bash·shell·gnu·parallel
似霰6 天前
Linux Shell 脚本编程——核心基础语法
linux·shell
似霰6 天前
Linux Shell 脚本编程——脚本自动化基础
linux·自动化·shell
偷学技术的梁胖胖yo7 天前
Shell脚本中连接数据库查询数据报错 “No such file or directory“以及函数传参数组
linux·mysql·shell
纵有疾風起16 天前
【Linux 系统开发】基础开发工具详解:软件包管理器、编辑器。编译器开发实战
linux·服务器·开发语言·经验分享·bash·shell
gis分享者18 天前
Shell 脚本中如何使用 here document 实现多行文本输入? (中等)
shell·脚本·document·多行·文本输入·here
柏木乃一18 天前
基础IO(上)
linux·服务器·c语言·c++·shell
angushine19 天前
CPU脚本并远程部署
shell
赵民勇23 天前
Linux/Unix中install命令全面用法解析
linux·shell
gis分享者24 天前
Shell 脚本中如何使用 trap 命令捕捉和处理信号(中等)
shell·脚本·信号·处理·trap·捕捉