数学运算
在之前的文档中,我们已经接触过数学运算了,但是没有详细的说明。所以,这一篇文档就来好好聊聊数学运算在 Shell 脚本编程中的运用。
在 Shell 中,进行数学运算有两种方式,如下表所示:
语法 | |
|---|---|
方法一 |
|
方法二 |
|
使用 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 |
除了上面这些外,还有 +、 -、 *、 /、 % 。下面来演示一下:
需要注意这些事项:
在 Shell 编程中,通常 0 表示真,非 0 表示假。而 expr 不符合着约定。
针对
%、>等操作符,属于 Shell 的保留字符,需要使用\转义符转义。操作符两边必须要留有空格。
参与运算的数值必须都是整数
那么如何判断输入的值为整数呢?如下示例:
对输入的 input 变量使用 expr 命令进行运算,如果正确则 $? 为0,否则为大于0的值(2)。
使用 $(())
除了使用 expr 命令外,我们还可以使用 $(()) 语法来进行算数运算,而且更加的方便,如下示例:
比较两种做法,我还是觉得使用 $(()) 更加的方便,不需要进行转义以及对空格不敏感。
但如果是对两个运算数字进行比较的话,还是建议使用 expr ,因为 $(()) 进行比较运算返回的结果不一定正确。比如进行等于操作:
这是因为 Shell 脚本语法的不严谨导致的。
使用 bc
不管是 expr 还是 $(()) 都不支持浮点数的运算,而 bc 是 bash 内建的运算器,支持浮点数的运算。
需要注意的是,如果不适用 scale 命令指定精度的话(即 scale 默认为 0),bc 也只精确到个位为止。
bc 支持加(+ )减(- )乘(* )除(/ )以及求余(% )和指数(^ )运算。我们在终端中,使用 bc 就可以进行交互式运算:

如果我们需要指定精度:

上面的演示都是基于 bc 提供的交互式环境,那么如果我需要通过程序来调用 bc 进行运算呢?利用管道符就可以完成:
附录: dc 和 bc
关于 dc 和 bc 的介绍,我是在 《Linux 就是这个范儿》这本书上看到的,我建议大家可以去看这本书中的原文,更加的精彩。另外,这本书本身也是我非常推荐的,因为它有个性。
dc 和 bc 其实不仅仅是一个计算器,而是一门语言,他们也都支持分支和循环结构,拥有 图灵完备(Turing Complete) 的特性。
dc(Desk calculator) 是最古老的 Unix 语言,比 C 语言还要更早。而 bc(basic calculator) 要稍微晚一些,于 1975 年的 Version 6 Unix 中第一次发行。
bc 和 dc 有很紧密的渊源,不仅仅是因为他们有着相同的作者——Rebert Morris 和 Lorinda 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。