使用 expr, $(()), (())

使用 expr, $(()), (())

在 shell 脚本中我们可以expr $a*$b$(($a+$b)).

但为什么不只是使用(($a+$b)),因为在任何资源中它都是(())用于整数计算的。

那么,$(())当有变量时,我们应该使用什么来代替整数值呢?$(())当变量可以接收浮点值时,我们应该使用什么来代替呢?

答案1

  1. 对于算术来说,expr这是古老的。不要使用它。*

  2. $((...))并且((...))非常相似。两者都只进行整数计算。区别在于$((...))返回计算结果和 ((...))不返回计算结果。因此$((...))在语句中很有用echo

     $ a=2; b=3; echo "$((a*b))"
     6
    

    ((...))当您想要分配变量或设置退出代码时很有用:

     $ a=3; b=3; ((a==b)) && echo yes
     yes
    
  3. 如果您想要浮点计算,请使用bcawk

    $ 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 标志的原因是它是最简单的错误处理方式:如果发生错误则停止。

相关内容