expr
似乎不喜欢括号(在数学中用于显式运算符优先级):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
bash中如何表示运算符优先级?
答案1
您可以使用算术展开式来代替。
echo "$(( 3 * ( 2 + 1 ) ))"
9
在我个人看来,这看起来比使用expr
.
从man bash
算术扩展 算术展开允许计算算术表达式并替换结果。算术展开式的格式为:
$((expression))
该表达式被视为位于双引号内,但括号内的双引号不会被特殊处理。表达式中的所有标记都会经历参数扩展、字符串扩展、命令替换和引号删除。算术展开式可以嵌套。
评估是根据下面算术评估下列出的规则进行的。如果表达式无效,bash 将打印一条消息指示失败并且不会发生替换。
答案2
使用let
bash 内置命令的另一种方法:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
笔记
作为@Stéphane Chazelas 指出,为了便于阅读,bash
您应该使用或((...))
进行算术运算。expr
let
为了便于移植,请使用$((...))
类似@伯恩哈德回答。
答案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
和((...))
仅适用于ksh
、zsh
和bash
。$((...))
如果需要对其他 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 语法。