zenith-docs 1.0.0 Help

数学运算

在之前的文档中,我们已经接触过数学运算了,但是没有详细的说明。所以,这一篇文档就来好好聊聊数学运算在 Shell 脚本编程中的运用。

在 Shell 中,进行数学运算有两种方式,如下表所示:

语法

方法一

expr $num1 operator $num2

方法二

$(($num1 operator $num2 ))

使用 expr

expr 支持下表所示的这些操作符:

操作符

含义

num1 | num2

num1 不为空且非0,返回 num1;否则返回 num2

num1 & num2

num1 不为空且非0,返回 num1;否则返回 0

num1 < num2

num1 小于 num2,返回1,否则返回0

num1 <= num2

num1 小于等于 num2,返回1,否则返回0

num1 = num2

num1 等于 num2,返回1,否则返回0

num1 != num2

num1 不等于 num2,返回1,否则返回0

num1 > num2

num1 大于 num2,返回1,否则返回0

num1 >= num2

num1大于等于num2,返回1,否则返回0

除了上面这些外,还有 +-*/% 。下面来演示一下:

expr 3 \% 2 ## 输出: 1 expr 3 \* 2 ## 输出: 6 expr 0 \| 1 ## 输出: 1 expr 2 & 2 ## 输出: 2 expr 3 \< 2 ## 输出: 0

需要注意这些事项:

  • 在 Shell 编程中,通常 0 表示真,非 0 表示假。而 expr 不符合着约定。

  • 针对 %> 等操作符,属于 Shell 的保留字符,需要使用 \ 转义符转义。

  • 操作符两边必须要留有空格。

  • 参与运算的数值必须都是整数

那么如何判断输入的值为整数呢?如下示例:

#!/bin/bash read -p "Please input your age:" input expr $input + 1 2> /dev/null if [ $? -gt 0 ];then echo 'error' fi

对输入的 input 变量使用 expr 命令进行运算,如果正确则 $? 为0,否则为大于0的值(2)。

使用 $(())

除了使用 expr 命令外,我们还可以使用 $(()) 语法来进行算数运算,而且更加的方便,如下示例:

echo $((3%2)) ## 输出: 1 echo $((3*2)) ## 输出: 6 echo $((0|1)) ## 输出: 1 echo $((2&2)) ## 输出: 2 echo $((3<2)) ## 输出: 0

比较两种做法,我还是觉得使用 $(()) 更加的方便,不需要进行转义以及对空格不敏感。

但如果是对两个运算数字进行比较的话,还是建议使用 expr ,因为 $(()) 进行比较运算返回的结果不一定正确。比如进行等于操作:

$ echo $((3=3)) -bash: 3=3: attempted assignment to non-variable (error token is "=3")

这是因为 Shell 脚本语法的不严谨导致的。

使用 bc

不管是 expr 还是 $(()) 都不支持浮点数的运算,而 bc  是 bash 内建的运算器,支持浮点数的运算。

需要注意的是,如果不适用 scale 命令指定精度的话(即 scale 默认为 0),bc 也只精确到个位为止。

bc 支持加(+ )减(- )乘(* )除(/ )以及求余(% )和指数(^ )运算。我们在终端中,使用 bc 就可以进行交互式运算:

image.png

如果我们需要指定精度:

image.png

上面的演示都是基于 bc 提供的交互式环境,那么如果我需要通过程序来调用 bc 进行运算呢?利用管道符就可以完成:

echo "23+25" | bc ## 输出: 48 echo "scale=2;23/5" | bc ## 输出: 4.60

附录: dc 和 bc

关于 dc 和 bc 的介绍,我是在 《Linux 就是这个范儿》这本书上看到的,我建议大家可以去看这本书中的原文,更加的精彩。另外,这本书本身也是我非常推荐的,因为它有个性。

dc 和 bc 其实不仅仅是一个计算器,而是一门语言,他们也都支持分支和循环结构,拥有 图灵完备(Turing Complete) 的特性。

dc(Desk calculator) 是最古老的 Unix 语言,比 C 语言还要更早。而 bc(basic calculator) 要稍微晚一些,于 1975 年的 Version 6 Unix 中第一次发行。

bc 和 dc 有很紧密的渊源,不仅仅是因为他们有着相同的作者——Rebert MorrisLorinda Cherry 。前者被普遍认为是计算机安全的先驱人物, Linux 延续至今的用于用户验证的密码加密体系就是他发明的。他发明了 确保计算机安全的三条黄金定律

  • 不要拥有计算机

  • 不要打开计算机

  • 不要使用计算机

而 Lorinada Cherrry,她是一位程序员。嗯,是女字旁的她,我没有写错。她令人敬仰的是,和 Rebert Morris 共同完成了 dc 和 bc。而且,她还和 BrianW.Kernighan 共同开发了 Troff 的预处理器 eqn。

dc 非常的强大,但是非常的不人性化,使用逆波兰式来表达算式。我们现在使用的都是代数标记法,也称之为中缀表达式,比如 1 + 1, 2 * 3。而逆波兰式也 成为后缀表达式,比如 1 1 +,2 3 *。

因为 dc 已经非常强大了,所以没有必要再造一个轮子。所以创造了 dc 的前端程序,bc。而现在的 Linux 系统所提供的 GNU 版本的 dc 和 bc 会将代码编 译成字节码,然后由虚拟机去解释执行。

总结

这一篇文档中详细描述了如何在 Shell 脚本编程中应用数值的运算,分别介绍了三种方法,分别是 expr$(()) 以及 bc

Last modified: 04 August 2024