expr 算术中的括号:3 * (2 + 1)

expr 算术中的括号:3 * (2 + 1)

expr似乎不喜欢括号(在数学中用于显式运算符优先级):

expr 3 * (2 + 1)
bash: syntax error near unexpected token `('

bash中如何表示运算符优先级?

答案1

您可以使用算术展开式来代替。

echo "$(( 3 * ( 2 + 1 ) ))"
9

在我个人看来,这看起来比使用expr.

man bash

算术扩展 算术展开允许计算算术表达式并替换结果。算术展开式的格式为:

         $((expression))

该表达式被视为位于双引号内,但括号内的双引号不会被特殊处理。表达式中的所有标记都会经历参数扩展、字符串扩展、命令替换和引号删除。算术展开式可以嵌套。

评估是根据下面算术评估下列出的规则进行的。如果表达式无效,bash 将打印一条消息指示失败并且不会发生替换。

答案2

使用letbash 内置命令的另一种方法:

$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9

笔记

作为@Stéphane Chazelas 指出,为了便于阅读,bash您应该使用或((...))进行算术运算。exprlet

为了便于移植,请使用$((...))类似@伯恩哈德回答

答案3

没有理由expr在现代 shell 中使用算术。

POSIX 定义了$((...))扩展运算符。因此,您可以在所有兼容 POSIX 的 shell 中使用它(sh所有现代 Unix 类 shell,dash、bash、yash、mksh、zsh、posh、ksh...)。

a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))

ksh还引入了一个let内置函数,它传递相同类型的算术表达式,不会扩展为某个东西,而是根据表达式是否解析为 0 返回退出状态,如下所示expr

if let 'a = 3 * (2 + 1)'; then
  echo "$a is non-zero"
fi

expr然而,由于引用使其变得尴尬且不太易读(与当然的程度不同),ksh还引入了((...))另一种形式:

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
  echo "$a is non-zero and 3 > 1"
fi
((a+=2))

它更清晰,应该使用它。

let((...))仅适用于kshzshbash$((...))如果需要对其他 shell 的可移植性,则应该首选该语法,expr只有 POSIX 之前的类似 Bourne 的 shell(通常是 Bourne shell 或 Almquist shell 的早期版本)才需要该语法。

在非 Bourne 方面,有一些带有内置算术运算符的 shell:

  • csh/ tcsh(实际上是第一个内置算术求值的 Unix shell):

    @ a = 3 * (2 + 1)
    
  • akanga(基于rc

    a = $:'3 * (2 + 1)'
    
  • 作为历史记录,1989 年在 usenet 上发布的 Almquist shell 的原始版本有一个expr内置函数(实际上与 合并test),但后来被删除。

答案4

使用括号加引号:

expr 3 '*' '(' 2 '+' 1 ')'
9

引号可防止 bash 将括号解释为 bash 语法。

相关内容