Shell脚本中的几种计算方式
expr
这是我常用的一个命令,它不仅可以实现数值运算,还可以进行数值或字符串的比较,字符串的匹配、提取、统计长度,甚至可以判断变量或参数是否为整数、是否为空、是否为0等。
-
处理算术表达式
- expr命令可以处理普通的算术操作,但是只能是整数1,并且算术表达式优先级低于字符串表达式,高于逻辑关系表达式。
- +、-、*、/、%,操作符的两边都要用空格隔开。并且需要注意一些特殊的字符,例如
*
、/
、()
等等。这些字符在shell中有特殊含义,需要使用 \ 进行转义或者 ‘’ 包围。 - 例子
- 直接返回计算结果
- 使用变量进行计算,同时对 * 进行了转义
- 未进行转义的情况
- 对非整数进行处理的情况
-
处理字符串表达式
-
字符串表达式的优先级高于数值表达式和逻辑关系表达式
-
模式匹配
-
expr STRING : REGEX
等价于expr match STRING REGEX
-
两个参数都会被视为字符格式,第二个参数会被作为正则表达式解释,并且它默认隐含前缀 ^ 。
-
如果匹配成功,且REGEX使用了’\(‘和’\)’2,则此表达式返回匹配到的。注:只有第一个’\(…\)‘会引用返回的值;其余的’\(…\)'只在正则表达式分组时有意义。
-
如果未使用’\(‘和’\)’,则返回匹配的字符数。
-
如果匹配失败,如果REGEX中使用了’\(‘和’\)’,则此表达式返回空字符串,否则返回为0。
-
-
返回字符串子串
expr substr STRING POSITION LENGTH
- 返回STRING字符串中从POSITION开始,长度最大为LENGTH的字符串子串。如果POSITION或LENGTH为负数、0或非数值,则返回空字符串。3
-
子字符串中任意字符在字符串中的最前一个位置
expr index STRING CHARSET
- CHARSET中任意单个字符在STRING中最前面的字符位置。如果在STRING中完全不存在CHARSET中的字符,则返回0。4
-
返回字符串长度
expr length STRING
- 返回STRING的字符数
-
处理关键字
+ TOKEN
- 将字符串TOKEN解析为普通字符串,即使TOKEN是像match或操作符"/"一样的关键字。
-
-
逻辑表达式
expr
支持普通的逻辑连接和逻辑关系,但是它的优先级最低。
表达式 | 含义 |
---|---|
ARG1 | ARG2 | 如果ARG1非0,则返回ARG1的值,否则返回ARG2。 |
但如果任意一个参数为空,则报错,除非空字符串使用引号包围 | |
ARG1 & ARG2 | 如果两个参数都非0,则返回ARG1,否则返回0。 |
但任意一个参数为空,则报错,除非空字符串使用引号包围 | |
ARG1 < ARG2 | ARG1 小于ARG2 |
ARG1 <= ARG2 | ARG1 小于或等于ARG2 |
ARG1 = ARG2 | ARG1 等于ARG2 |
ARG1 != ARG2 | ARG1 不等于ARG2 |
ARG1 >= ARG2 | ARG1 大于或等于ARG2 |
ARG1 > ARG2 | ARG1 大于ARG2 |
注: |和& 在使用中都需要转义,或者用 ‘’ 括起来
对于某个参数是空的情况
注:除了 |和& ,其余的逻辑符号在表达式为真时,返回1,否则返回0.这与程序返回值对比看有点别扭。
我们依旧不能忘记特殊字符的转义,下面的 > 被解析成了输出重定向
$[ operation ]
$[]
符号的方便之处在于它对方括号内的空格无太严格的要求,同时方括号内的运算符不需要进行转义,但是它依旧只能处理整数运算。
let
let命令属于内建命令,执行它的开销要少于上面两种,并且还提供了求幂运算符**
、自加自减等。
let arg [arg ...] #arg代表运算式
使用let命令时需要注意一些细节:
- let表达式内变量不用加$
- 运算符两边不可以有空格,有的话就必须用单引号或者双引号括起来
- let后面必须是赋值表达式,即为变量赋值
与expr等命令不同,expr 3 + 2
将返回5,而形如let 3+2
是没有意义的。
- 求幂示例
- 自增示例
使用双括号
(())
也属于内建命令,并且依然只支持整型计算,双括号内的运算符不需要进行转义。
- 它的命令格式形如 ((expression)), 其中 expression 可以是任意的比较或者赋值表达式5。
- ((expression)) ,如果表达式的结果为0,那么返回的退出状态码为1,而一个非零值的表达式所返回的退出状态码将为0。
- ((expression)) 若用于自增自减等常用的算术运算时,与let命令类似
- ((expression)) 常用来计算并测试算术表达式,搭配c风格的for,while,if等
bash内建计算器
bc
命令作为 一个任意精度的计算器语言 ,它可以补充浮点数计算的能力,bc
甚至可以称得上是一种编程语言了,它支持变量、数组、输入输出、分支结构、循环结构、函数等基本的编程元素,当然它的开销相对于上面那些来说也是最大的。在shell脚本中我们一般通过管道和输入重定向来使用 bc,而在命令行环境中,我们直接输入bc
即可进入交互式的数学计算。
下面是bc命令的一些常用选项:
选项 | 说明 |
---|---|
-h | --help | 显示帮助信息 |
-v | --version | 显示版本信息 |
-l | --mathlib | 使用标准数学库 |
-i | --interactive | 强制交互 |
-w | --warn | 显示 POSIX 的警告信息 |
-s | --standard | 使用 POSIX 标准来处理 |
-q | --quiet | 不显示欢迎信息 |
- 交互式使用示例
图中前四行是版本及版权信息,使用-q
选项可以不输出,接下来我们便可以像使用计算器一样输入计算式,计算结果会在下一行输出,接下来输入quit
退出程序
bc
中可以使用变量,并且自定义函数
bc
的四个内置变量
变量名 | 说明 |
---|---|
scale | 指定精度,也即小数点后的位数;默认为 0,也即不使用小数部分 |
ibase | 指定输入的数字的进制,默认为十进制 |
obase | 指定输出的数字的进制,默认为十进制 |
last或者. | 表示最近打印的数字 |
scale
默认为0,当指定大于0的值时,就可以输出小数点后面的位了
八进制的144即十进制的100,八进制的10即十进制的8,.
即重复输出最后的数字
- 内置函数
&esmp;bc
命令还有一些内置函数,要想使用这些内置函数,在输入 bc 命令时需要使用-l
选项启用数学库
函数名 | 说明 |
---|---|
s(var) | 计算var的正弦值,var是弧度值 |
c(var) | 计算var的余弦值,var是弧度值 |
a(var) | 计算var的反正切值,返回弧度值 |
l(var) | 计算var的自然对数 |
e(var) | 求 e 的var次方 |
j(n, m) | 贝塞尔函数,计算从 n 到m的阶数 |
在一行内的多个表达式需要用;
隔开
-
shell脚本中使用
bc
一般会借助管道命令或者输入重定向-
借助管道命令
类似于:echo "expression" | bc
将单个或多个表达式通过管道命令传给
bc
可以直接输出计算结果。
同时也可以将计算结果赋值给变量:var=$(echo "expression" | bc)
利用shell中的变量进行计算:
或者调用它的内置变量
-
借助输入重定向
类似于:
bc << EOF expressions EOF
-
当有多个表达式时,这样书写比较方便清晰。