Nic*_*oul 72 shell quoting arithmetic expr
expr 似乎不喜欢括号(在数学中用于显式运算符优先级):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Run Code Online (Sandbox Code Playgroud)
如何在bash中表达操作员优先级?
Ber*_*ard 86
您可以改用算术扩展。
echo "$(( 3 * ( 2 + 1 ) ))"
9
Run Code Online (Sandbox Code Playgroud)
在我个人看来,这看起来比使用expr.
从 man bash
算术扩展 算术扩展允许对算术表达式求值并替换结果。算术展开的格式为:
Run Code Online (Sandbox Code Playgroud)$((expression))该表达式被视为在双引号内,但括号内的双引号不会被特殊处理。表达式中的所有标记都经过参数扩展、字符串扩展、命令替换和引号删除。算术扩展可以嵌套。
评估是根据下面在算术评估下列出的规则进行的。如果表达式无效,bash 会打印一条消息指示失败并且不会发生替换。
cuo*_*glm 48
使用let内置 bash 的另一种方法:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
Run Code Online (Sandbox Code Playgroud)
笔记
正如@Stéphane Chazelas 所指出的那样,bash您应该((...))用来进行算术运算expr或let为了易读性。
为了可移植性,使用$((...))像@Bernhard answer。
Sté*_*las 42
没有理由expr在现代 shell 中使用算术。
POSIX 定义了$((...))扩展运算符。所以你可以在所有符合 POSIX 的 shell 中使用它(sh所有现代类 Unix 的shell ,dash、bash、yash、mksh、zsh、posh、ksh ......)。
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
Run Code Online (Sandbox Code Playgroud)
ksh还引入了一个let内置函数,它传递了相同类型的算术表达式,它不会扩展为某些内容,而是根据表达式是否解析为 0 返回退出状态,例如expr:
if let 'a = 3 * (2 + 1)'; then
echo "$a is non-zero"
fi
Run Code Online (Sandbox Code Playgroud)
但是,由于引用使它变得笨拙且不太清晰(expr与当然的程度不同),因此ksh还引入了((...))另一种形式:
if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
echo "$a is non-zero and 3 > 1"
fi
((a+=2))
Run Code Online (Sandbox Code Playgroud)
这更清晰,应该使用。
let和((...))仅在ksh、zsh和 中可用bash。的$((...))语法应首选如果需要移植到其他外壳,expr只需要用于预POSIX类似Bourne壳(典型的是Bourne壳或壳Almquist的早期版本)。
在非 Bourne 前端,有一些带有内置算术运算符的 shell:
csh/ tcsh(实际上是第一个内置算术计算的 Unix shell):
@ a = 3 * (2 + 1)
Run Code Online (Sandbox Code Playgroud)akanga(基于rc)
a = $:'3 * (2 + 1)'
Run Code Online (Sandbox Code Playgroud)作为历史记录,1989 年在 usenet 上发布的 Almquist shell 的原始版本有一个expr内置(实际上与 合并test),但后来被删除了。
Gil*_*il' 18
expr是一个外部命令,它不是特殊的 shell 语法。因此,如果您想expr查看 shell 特殊字符,则需要通过引用它们来保护它们免受 shell 解析。此外,expr需要将每个数字和运算符作为单独的参数传递。因此:
expr 3 \* \( 2 + 1 \)
Run Code Online (Sandbox Code Playgroud)
除非您在 1970 年代或 1980 年代的老式 unix 系统上工作,否则几乎没有理由使用expr. 在过去,shell 没有执行算术的内置方法,您必须调用该expr实用程序。所有 POSIX shell 都通过算术扩展语法内置了算术。
echo "$((3 * (2 + 1)))"
Run Code Online (Sandbox Code Playgroud)
该构造$((…))扩展为算术表达式的结果(以十进制表示)。与大多数 shell 一样,Bash 仅支持整数算术模 2 64(或模 2 32用于旧版本的 bash 和 32 位机器上的其他一些 shell)。
当您想要执行赋值或测试表达式是否为 0 但不关心结果时,Bash 提供了额外的便利语法。该构造也存在于 ksh 和 zsh 中,但不存在于普通 sh 中。
((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …
Run Code Online (Sandbox Code Playgroud)
除了整数运算之外,expr还提供了一些字符串操作函数。这些也包含在 POSIX shell 的特性中,除了一个:expr STRING : REGEXP测试字符串是否与指定的正则表达式匹配。没有外部工具,POSIX shell 无法做到这一点,但 bash 可以[[ STRING =~ REGEXP ]](使用不同的正则表达式语法- expr是经典工具并使用 BRE,bash 使用 ERE)。
除非您维护在 20 年前的系统上运行的脚本,否则您不需要知道它expr曾经存在过。使用 shell 算法。
Nic*_*oul 14
使用带引号的括号:
expr 3 '*' '(' 2 '+' 1 ')'
9
Run Code Online (Sandbox Code Playgroud)
引号可防止 bash 将括号解释为 bash 语法。