在 shell 脚本中我们可以expr $a*$b
用$(($a+$b))
.
但为什么不只是使用(($a+$b))
,因为在任何资源中它都是(())
用于整数计算的。
那么,$(())
当有变量时,我们应该使用什么来代替整数值呢?$(())
当变量可以接收浮点值时,我们应该使用什么来代替呢?
答案1
对于算术来说,
expr
这是古老的。不要使用它。*$((...))
并且((...))
非常相似。两者都只进行整数计算。区别在于$((...))
返回计算结果和((...))
不返回计算结果。因此$((...))
在语句中很有用echo
:$ a=2; b=3; echo "$((a*b))" 6
((...))
当您想要分配变量或设置退出代码时很有用:$ a=3; b=3; ((a==b)) && echo yes yes
如果您想要浮点计算,请使用
bc
或awk
:$ echo '4.7/3.14' | bc -l 1.49681528662420382165 $ awk 'BEGIN{print 4.7/3.14}' 1.49682
*顺便说一句,expr
当 glob 不够好并且需要 POSIX 方法来处理正则表达式时,它对于字符串处理仍然很有用。
答案2
expr 已经很老了,但我认为它有一个有限的用途。假设你想搜索一个字符串。如果你想让 grep 保持 POSIX,你需要使用管道:
if echo november | grep nov
then
: do something
fi
expr 可以在没有管道的情况下执行此操作:
if expr november : nov
then
: do something
fi
唯一的问题是 expr 适用于锚定字符串,因此如果您想在开头之后进行匹配,则需要更改 REGEXP:
if expr november : '.*ber'
then
: do something
fi
关于(( ))
,这个构造不是 POSIX,所以应该避免。
关于$(( ))
,您不必包含美元符号:
$ fo=1
$ go=2
$ echo "$((fo + go))"
3
答案3
看起来以下程序的作用或多或少相同,并且没有真正的不同。但事实并非如此。
#!/bin/bash
s=-1000
for (( i=0; i<1000000; i++ )); do
s=$((s+1))
done
echo "$s"
这是实现这一点的正确方法。表达式 s+1 由 shell 计算并可以分配给变量。
#!/bin/bash
s=-1000
for (( i=0; i<1000000; i++ )); do
s=`expr "$s" + 1`
done
echo "$s"
这里的表达式将由程序 expr 计算,该程序不是内置的 shell,而是外部 Unix 程序。因此,不能简单地加 1,并且必须启动 sa 程序,并且必须读取其输出并将其写入变量。启动一个项目需要大量的资源和时间。并且这个程序运行了1000000次。所以程序会比之前慢很多。尽管如此,代码仍然可以正常工作。
#!/bin/bash -e
s=-1000
for (( i=0; i<1000000; i++ )); do
((s=s+1))
done
echo "$s"
如果未设置 -e 标志,程序也将正常工作。但如果在s=-1时设置-e,则计算((s=s+1))。表达式 s=s+1 的计算结果为 0,并且 ((0)) 的退出代码 >0,这被 shell 解释为错误,并且 shell 退出程序。
设置 -e 标志的原因是它是最简单的错误处理方式:如果发生错误则停止。