如何在bash条件表达式中使用变量?

时间:2016-11-30 15:18:59

标签: bash shell

我想就如何在bash条件表达式[[...]]中最好地使用变量做一些解释。

我通常以这种方式写if语句:

var=1;
# some code...
if [[ $var -eq 1 ]]; then echo "ok"; else echo "fail"; fi

并按照我的预期返回ok

现在我在一些脚本中看到了类似的声明:

var=1;
# some code...
if [[ var -eq 1 ]]; then echo "ok"; else echo "fail"; fi

唯一的区别是条件表达式$中缺少参数扩展字符[[...]]

我实际上希望此语句给出错误,但接受此语法并返回ok字符串。

我使用bash(GNU bash,版本4.3.46),zsh(5.1.1),ksh(93u + 2012-08-01)和busybox {测试了此语句{1}}(BusyBox v1.23.2)。

我只收到busybox shell的错误:

ash

我在ash: var: bad number 手册页的bash段中看到:

  

在表达式中,shell变量也可以通过名称引用,而不使用参数扩展语法

但我在ARITHMETIC EVALUATION段落中找不到与参数扩展有关的任何特殊内容。

那么,在引用变量时条件表达式是否应包含CONDITIONAL EXPRESSIONS?为什么?

2 个答案:

答案 0 :(得分:3)

此处的触发器为-eq;因为它被定义为执行整数比较,所以它的操作数在算术上下文中被计算。但是,这没有明确记录。

但您应该使用$[[是一个扩展,因此无法保证它在定义此类构造的每个shell中的行为都相同。实际上,我甚至不认为[[ var -eq 3 ]]将在同一个shell的未来版本中继续以这种方式运行。但是,(( var == 3 )) ,记录为执行var的扩展,因为您处于显式算术上下文中。

答案 1 :(得分:1)

查看bash手册页的Compound Commands部分。特别是,以下内容:

   ((expression))
          The  expression  is  evaluated  according to the rules described below
          under ARITHMETIC EVALUATION.  If the value of the expression is non-zero,
          the return status is 0; otherwise the return status is 1.  This is exactly
          equivalent to `let "expression"`.

   [[ expression ]]
          Return a status of 0 or 1 depending on the evaluation of the conditional
          expression expression.  Expressions are composed of the primaries
          described below  under  CONDITIONAL EXPRESSIONS.

如果您正在评估需要算术的内容,请使用算术评估,并查看CONDITIONAL EXPRESSIONS部分,了解您可以使用[[ ... ]]执行的各种操作。双方括号中的条件可以评估字符串和整数,有时候它们的工作方式相同......有时候不是。

在bash手册页的CONDITIONAL EXPRESSIONS下:

   string1 == string2
   string1 = string2
          True  if the strings are equal.  = should be used with the test command for POSIX conformance.  When used with the [[ command, this performs pattern
          matching as described above (Compound Commands).
...
   arg1 OP arg2
          OP is one of -eq, -ne, -lt, -le, -gt, or -ge.  These arithmetic binary operators return true if arg1 is equal to, not equal to, less than, less than
          or equal to, greater than, or greater than or equal to arg2, respectively.  Arg1 and arg2 may be positive or negative integers.

显然,字符串“1”是字符串“1”,因此,如果n=1,您将$n与字符串"1"进行比较,则会受到影响。但你应该知道你在做什么,这不是数字比较。同样,<>不是数字比较,它们是字符串比较。因此,在"1" < "2"时,您可能会对"11" < "2"感到惊讶。

那就是说,bash对你要求它评估什么样的条件感到宽容:

bash-4.4$ n=1
bash-4.4$ [[ n -eq 1 ]] && echo yes
yes
bash-4.4$ [[ $n -eq 1 ]] && echo yes
yes
bash-4.4$ (( n == 1 )) && echo yes
yes
bash-4.4$ (( n = 2 )) && echo yes
yes
bash-4.4$ echo "$n"
2

第一个可行,因为n在这个上下文中不能是变量,所以bash将其视为此类。但你不应该依赖这种行为。在条件表达式中对变量使用美元符号,并坚持使用bash口头禅,“总是引用你的变量”。

在bash中的双方括号表达式中,如果您希望比较为整数,则应使用算术二元运算符。

请注意,您的busybox版本似乎使用ash,而非bash。 Ash是“Almquist shell”,是一种比bash更古老的POSIX shell,写于20世纪80年代后期。 Ash是FreeBSD中/bin/sh的基础,除了由于其较小的尺寸而经常优于嵌入式系统中的bash(因此也是busybox)。

您可能需要考虑编写POSIX shell脚本而不是Bash shell脚本。这将意味着简化一些事情,以及为其他人跳过一些箍。 POSIX不包含双方括号表达式,但 允许[ "$n" -eq 1 ][ $(( n + 1 )) -eq 2 ]之类的内容。它会在busybox中运行。 :)

相关问题