shell对于数值计算支持的不是特别好,而且bash shell的数学操作符只支持整数运算(z shell提供了完整的浮点数运算),如果想要进行浮点数运算,需要采用一些其他方法,下面我们总结一下shell中如何进行数学计算。

1. expr命令

expr命令我们可以进行一些简单的数学运算或者字符串运算,下面是expr命令支持的操作符(参见man文档):

操作符 说明
ARG1 | ARG2 如果两个参数都非null或者0,返回ARG1;否则返回ARG2。需转义
ARG1 & ARG2 如果两个参数都非null或者0,返回ARG1;否则返回0。需转义
ARG1 < ARG2 如果ARG1小于ARG2,返回1;否则返回0。需转义
ARG1 <= ARG2 如果ARG1小于等于ARG2,返回1;否则返回0。需转义
ARG1 = ARG2 如果ARG1等于ARG2,返回1;否则返回2
ARG1 != ARG2 如果ARG1不等于ARG2,返回1;否则返回2
ARG1 >= ARG2 如果ARG1大于等于ARG2,返回1;否则返回2。需转义
ARG1 > ARG2 如果ARG1大于ARG2,返回1;否则返回2。只能用于数学运算。需转义
ARG1 + ARG2 返回ARG1与ARG2的算术运算和。只能用于数学运算
ARG1 - ARG2 返回ARG1与ARG2的算术运算差。只能用于数学运算
ARG1 * ARG2 返回ARG1与ARG2的算术运算积。需转义
ARG1 / ARG2 返回ARG1与ARG2的算术运算商。
ARG1 % ARG2 返回ARG1与ARG2的算术运算余数。
STRING : REGEXP 如果REGEXP匹配到了STRING中的某个模式,返回该模式匹配
match STRING REGEXP 和STRING : REGEXP相同
substr STRING POS LENGTH 范围起始位置为POS(从1开始计数),长度为LENGTH个字符的子字符串
index STRING CHARS 返回在STRING中找到CHARS字符串的位置(以完整的单词计数);否则返回0
length STRING 返回字符串STRING的数值长度
+ TOKEN 将TOKEN解释成字符串,即使是个关键字(比如match或者'/')
( EXPRESSION ) 返回EXPRESSION的值。需转义

使用expr命令的注意事项:

  • expr的许多运算符都需要转义()或者用引号括起来,否则就会出错。需要转义的运算符已经在上面的表格中用红字标识出来
  • 涉及到比较的运算符使用如下规则进行比较:如果都是数字,则使用算术比较;如果有非数字,则使用字典序比较(ASCII序)
  • 变量与运算符之间必须有至少一个空格
    expr返回值:

表达式非null或者非0,返回0;表达式为null或者0,返回1;表达式有语法错误,返回2;其他错误返回3

2. 使用方括号

可以看到expr进行算术运算时很多运算符都需要转义,使用非常不方便,所以bash shell提供了一个简单的方法:在bash中,在将一个数学运算结果赋给某个变量时,可以使用美元符合方括号将数学表达式圈起来($[ operation ])相比expr,使用方括号有如下好处:

  • 在方括号内的所 有运算符不需要转义,shell会将他们解释为运算符,而非shell里面具有特殊含义的符号。
  • 方括号里面的操作符和运算符之间无需加空格,比如echo $[ 5 * 2 ]</span> 和<span class="lang:default decode:true crayon-inline ">echo $[5*2] 均可。
    注:shell中有一个test命令可以用来测试一些条件,而test也可以用方括号替代,但是那里的方括号与此处用于计算的方括号含义不同(要求也不同,表示test的方括号需要加空格),注意区分。

3. 浮点数运算

在bash shell中进行浮点数运算最常见的方法就是使用内建的bash计算器bc。默认情况下,bc只支持整数运算,要想支持浮点数运算,需要设置bc内建的scale变量,该变量的值表示小数点后的位数,默认为0.我们在shell脚本中,可以使用管道来进行浮点数运算,基本格式如下:

variable=`echo "options; expression" | bc`

比如下面的例子:

#!/bin/bash

# simple one
var=`echo "scale=4; 3.44 / 5" | bc`
echo "var=$var"

# complex one
var1=10.46
var2=43.67
var3=33.2
var4=71

var5=`bc << EOF
scale = 4
a1 = ( $var1 * $var2 )
b1 = ( $var3 * $var4 )
a1 + b1
EOF
`
echo "var5=$var5"

运行结果:

allan@ubuntu:temp$ sh test.sh 
var=.6880
var5=2813.9882