另一个对任何编程语言都很重要的特性是操作数字的能力。遗憾的是,对shell脚本来说,这
    个处理过程会比较麻烦。在shell脚本中有两种途径来进行数学运算。
    11.7.1 expr 命令
    最开始,Bourne shell提供了一个特别的命令用来处理数学表达式。expr命令允许在命令行
    上处理数学表达式,但是特别笨拙。
    $ expr 1 + 5
    6
    expr命令能够识别少数的数学和字符串操作符,见表11-1。
    image.png
    尽管标准操作符在expr命令中工作得很好,但在脚本或命令行上使用它们时仍有问题出现。
    许多expr命令操作符在shell中另有含义(比如星号)。当它们出现在在expr命令中时,会得到一
    些诡异的结果。
    $ expr 5 2
    expr: syntax error
    $
    要解决这个问题,对于那些容易被shell错误解释的字符,在它们传入expr命令之前,需要使
    用shell的转义字符(反斜线)将其标出来。
    $ expr 5 \
    2
    10
    $
    现在,麻烦才刚刚开始!在shell脚本中使用expr命令也同样复杂:
    $ cat test6
    #!/bin/bash
    # An example of using the expr command
    var1=10
    var2=20
    var3=$(expr $var2 / $var1)
    echo The result is $var3
    要将一个数学算式的结果赋给一个变量,需要使用命令替换来获取expr命令的输出:
    $ chmod u+x test6
    $ ./test6
    The result is 2
    $
    幸好bash shell有一个针对处理数学运算符的改进,你将会在下一节中看到。
    11.7.2 使用方括号
    bash shell为了保持跟Bourne shell的兼容而包含了expr命令,但它同样也提供了一种更简单
    的方法来执行数学表达式。在bash中,在将一个数学运算结果赋给某个变量时,可以用美元符和
    方括号($[ operation ])将数学表达式围起来。
    $ var1=$[1 + 5]
    $ echo $var1
    6
    $ var2=$[$var1 2]
    $ echo $var2
    12
    $
    用方括号执行shell数学运算比用expr命令方便很多。这种技术也适用于shell脚本。
    $ cat test7
    #!/bin/bash
    var1=100
    var2=50
    var3=45
    var4=$[$var1
    ($var2 - $var3)]
    echo The final result is $var4
    $
    运行这个脚本会得到如下输出。
    $ chmod u+x test7
    $ ./test7
    The final result is 500
    $
    同样,注意在使用方括号来计算公式时,不用担心shell会误解乘号或其他符号。shell知道它
    不是通配符,因为它在方括号内。
    在bash shell脚本中进行算术运算会有一个主要的限制。请看下例:
    $ cat test8
    #!/bin/bash
    var1=100
    var2=45
    var3=$[$var1 / $var2]
    echo The final result is $var3
    $
    现在,运行一下,看看会发生什么:
    $ chmod u+x test8
    $ ./test8
    The final result is 2
    $
    bash shell数学运算符只支持整数运算。若要进行任何实际的数学计算,这是一个巨大的限制。
    说明 z shell(zsh)提供了完整的浮点数算术操作。如果需要在shell脚本中进行浮点数运算,可
    以考虑看看z shell(将在第23章中讨论)。
    11.7.3 浮点解决方案
    有几种解决方案能够克服bash中数学运算的整数限制。最常见的方案是用内建的bash计算器,
    叫作bc。
    1. bc的基本用法
    bash计算器实际上是一种编程语言,它允许在命令行中输入浮点表达式,然后解释并计算该
    表达式,最后返回结果。bash计算器能够识别:
     数字(整数和浮点数)
     变量(简单变量和数组)
     注释(以#或C语言中的/ /开始的行)
     表达式
     编程语句(例如if-then语句)
     函数
    可以在shell提示符下通过bc命令访问bash计算器:
    $ bc
    bc 1.06.95
    Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
    This is free software with ABSOLUTELY NO WARRANTY.
    For details type ‘warranty’.
    12 5.4
    64.8
    3.156
    (3 + 5)
    25.248
    quit
    $
    这个例子一开始输入了表达式12 5.4。bash计算器返回了计算结果。随后每个输入到计
    算器的表达式都会被求值并显示出结果。要退出bash计算器,你必须输入quit。
    浮点运算是由内建变量scale控制的。必须将这个值设置为你希望在计算结果中保留的小数
    位数,否则无法得到期望的结果。
    $ bc -q
    3.44 / 5
    0
    scale=4
    3.44 / 5
    .6880
    quit
    $
    scale变量的默认值是0。在scale值被设置前,bash计算器的计算结果不包含小数位。在将
    其值设置成4后,bash计算器显示的结果包含四位小数。-q命令行选项可以不显示bash计算器冗
    长的欢迎信息。
    除了普通数字,bash计算器还能支持变量。
    $ bc -q
    var1=10
    var1
    4
    40
    var2 = var1 / 5
    print var2
    2
    quit
    $
    变量一旦被定义,你就可以在整个bash计算器会话中使用该变量了。print语句允许你打印
    变量和数字。
    2. 在脚本中使用bc
    现在你可能想问bash计算器是如何在shell脚本中帮助处理浮点运算的。还记得命令替换吗?
    是的,可以用命令替换运行bc命令,并将输出赋给一个变量。基本格式如下:
    variable=$(echo “options; expression” | bc)
    第一部分options允许你设置变量。如果你需要不止一个变量,可以用分号将其分开。
    expression参数定义了通过bc执行的数学表达式。这里有个在脚本中这么做的例子。
    $ cat test9
    #!/bin/bash
    var1=$(echo “scale=4; 3.44 / 5” | bc)
    echo The answer is $var1
    $
    这个例子将scale变量设置成了四位小数,并在expression部分指定了特定的运算。运行
    这个脚本会产生如下输出。
    $ chmod u+x test9
    $ ./test9
    The answer is .6880
    $
    太好了!现在你不会再只能用数字作为表达式值了。也可以用shell脚本中定义好的变量。
    $ cat test10
    #!/bin/bash
    var1=100
    var2=45
    var3=$(echo “scale=4; $var1 / $var2” | bc)
    echo The answer for this is $var3
    $
    脚本定义了两个变量,它们都可以用在expression部分,然后发送给bc命令。别忘了用美
    元符表示的是变量的值而不是变量自身。这个脚本的输出如下。
    $ ./test10
    The answer for this is 2.2222
    $
    当然,一旦变量被赋值,那个变量也可以用于其他运算。
    $ cat test11
    #!/bin/bash
    var1=20
    var2=3.14159
    var3=$(echo “scale=4; $var1 $var1” | bc)
    var4=$(echo “scale=4; $var3
    $var2” | bc)
    echo The final result is $var4
    $
    这个方法适用于较短的运算,但有时你会涉及更多的数字。如果需要进行大量运算,在一个
    命令行中列出多个表达式就会有点麻烦。
    有一个方法可以解决这个问题。bc命令能识别输入重定向,允许你将一个文件重定向到bc
    命令来处理。但这同样会叫人头疼,因为你还得将表达式存放到文件中。
    最好的办法是使用内联输入重定向,它允许你直接在命令行中重定向数据。在shell脚本中,
    你可以将输出赋给一个变量。
    variable=$(bc << EOF
    options
    statements
    expressions
    EOF
    )
    EOF文本字符串标识了内联重定向数据的起止。记住,仍然需要命令替换符号将bc命令的输
    出赋给变量。
    现在可以将所有bash计算器涉及的部分都放到同一个脚本文件的不同行。下面是在脚本中使
    用这种技术的例子。
    $ cat test12
    #!/bin/bash
    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 The final answer for this mess is $var5
    $
    将选项和表达式放在脚本的不同行中可以让处理过程变得更清晰,提高易读性。EOF字符串
    标识了重定向给bc命令的数据的起止。当然,必须用命令替换符号标识出用来给变量赋值的命令。
    你还会注意到,在这个例子中,你可以在bash计算器中赋值给变量。这一点很重要:在bash
    计算器中创建的变量只在bash计算器中有效,不能在shell脚本中使用。