使用 expr 时出现问题

使用 expr 时出现问题

我有两根弦

str1="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5"

str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2"

命令

result=` expr $str1`

返回正确的值,同时

result=` expr $str2`

回报expr: syntax error

答案1

以下将产生错误的结果:

str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2"
expr $str2

问题在于 shell 认为*是通配符文件 glob,并将其替换为当前目录中的文件列表。这不是你想要的。

expr是古老的。更现代的解决方案将使用 shell 的$((...))形式进行算术:

$ str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2"
$ echo "$((str2))"
15

shell 只进行整数运算。如果您确实想要浮点精确结果(此处恰好相同),请使用bc

$ echo "$str2" | bc -l
15.00000000000000000000

请注意,$str2用双引号括起来,以防止 shell 恶作剧。

答案2

当您将变量扩展到双引号之外时(如 中所示)expr $str2,会发生以下情况:

  1. 取变量的值。结果是一个字符串。
  2. 将值拆分为以空格分隔的块。结果是字符串列表。
  3. 将列表的每个元素解释为通配符模式,即通配。如果它与文件匹配,则用匹配列表替换该元素。如果它不匹配任何文件,则保留该元素。

例如,变量的值包含单词*,该单词将替换为当前目录中的文件名列表。

一般来说,始终在变量替换和命令替换两边加上双引号:"$stuff", "`stuff`"。看为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?仅当您知道并理解为什么需要省略引号时才省略引号。

在这种情况下,您需要执行步骤 2(拆分),因为expr需要将运算符和操作数放在单独的参数中。但步骤 3(将每个单词视为文件名通配符模式)一定不能发生。您可以通过关闭通配符来做到这一点:

result=`set -f; expr $str2`

在 ksh 或 bash 中,使用数组而不是字符串 — 但在这些 shell 中,您不会使用expr.

除非您需要将脚本移植到古老的 Bourne shell,否则不需要使用expr.算术表达式是标准 POSIX 功能。

result=$(($str2))

1分隔符可以通过IFS变量进行配置。

相关内容