let,expr和$ 之间的区别

我想知道究竟是什么区别

a=$[1+1] a=$((1+1)) let a=1+1 a=$(expr 1 + 1 ) 

所有4分配变量a和2,但有什么区别?

从我到目前为止发现的是,expr是慢的,因为它不是一个真正的shell内置。 但不仅如此。

所有这些都涉及算术,但以不同的方式处理,变量通过不同的方式创建。 其中一些特定于bash shell,而另一些则不是。

  • ((...))被称为算术扩展,这是典型的bashksh shell。 这允许进行简单的整数运算,但没有浮点数。 ((...))只是一个动作,所以$((..))代替了操作的输出。
  • $[...]是不推荐使用的算术扩展的旧语法。 另见 。 这可能会保留,以便旧的bash脚本不会中断。 这在ksh93ksh93 ,所以我的猜测是这种语法是特定于bash的。 注意 :空格在这里非常重要; 不要将$[1+1][ $a -eq $b ]类的东西混淆。 [使用空格称为test命令,您通常在决策部分中看到它。 它的行为和目的非常不同。
  • let是一个bashksh关键字,允许通过简单的算术评估进行变量创建。 如果您尝试分配一个字符串,例如let a="hello world"您将收到语法错误。 适用于bashksh93
  • $(...)是命令替换,您可以从中获取命令的输出并分配给变量。 你的命令是expr ,它接受位置参数,比如expr arg1 arg2 arg3 ,所以空格很重要。 它有点像整数算术的小命令行计算器,加上一些真/假和正则表达式的东西。 这是一个与shell无关的命令。

值得注意的是,算术扩展和命令替换是由POSIX标准指定的,而let$[...]则不是。

  • let命令执行算术评估 ,是内置的shell。

    • 运行此命令,您什么也得不到(仅评估):

       let 1+2 
  • $(( ))用于执行算术扩展 : 在此处阅读

    • 运行这个,你会得到一个错误(因为扩展):

       $((1+2)) 
  • $[ ]是算术扩展的旧语法:

    旧格式$ [expression]已弃用,将在即将发布的bash中删除。 Bash Man Page

  • expr是一个二进制命令,如果你想在命令子项中进行算术扩展,你可以使用它:

     echo $(expr 1 + 2) echo `expr 1 + 2` 

由于上面的一些答案特别提到ksh93 ,值得注意的是它可以做浮点数学,例如:

 $ print $((1.0/3)) 0.333333333333333333 

您可以使用printf控制输出的精度,例如:

 $ printf "%.4f\n" $((1.0/3)) 0.3333 

必须至少将一个参数指定为上面的浮点数。 如果两者都指定为整数,那么只进行整数数学运算,例如:

 $ print $((1/3)) 0 

当您需要在shell脚本中进行浮点数学运算时,这可能会有所帮助,因为您可以避免调用外部命令。

let在cron中不起作用。 我认为这是因为let拥有自己的环境。 使用$((...))因为它是POSIX。 例如,

 let x=1+2 echo x=$x 

在cron中,从shell运行时产生“x =”,但“x = 3”。

 x=$((1+2)) echo x=$x 

在所有情况下都得到“x = 3”。