2016-11-30 71 views
3

我想解释一下如何在bash条件表达式中最好地使用变量[[...]]如何在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,版本46年3月4日),zsh(5.1.1),ksh(93u + 2012-08-01)和busybox的ash(BusyBox的v1.23.2)这一说法。

我只能用busybox的外壳得到一个错误:

ash: var: bad number 

我在bash手册页看到,在ARITHMETIC EVALUATION段,即:

内的表达式,shell变量也可能是通过名称引用而不使用参数扩展语法

但是我没有发现任何特别的rel参见CONDITIONAL EXPRESSIONS段落中的参数扩展。

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

+0

'if [[var -eq 1]];然后回显“OK”;否则回显“失败”; fi'在'bash'和'ksh'上为我打印'失败' – anubhava

+0

@anubhava .. echo $ var返回什么? :) – ghoti

+0

'declare -p var'显示我 '-bash:declare:var:not found' – anubhava

回答

3

这里的触发器是-eq;因为它被定义为执行整数比较,所以它的操作数在算术上下文中被评估。虽然这没有明确记录。不过,您应该使用$[[是一个扩展,所以不能保证它在每个定义这样的构造的shell中表现得完全相同。事实上,我甚至不会假定[[ var -eq 3 ]]将继续在同一个shell的未来版本中以这种方式运行。 ((var == 3)),但是,由于您处于明确的算术环境中,因此被记录为执行var的扩展。

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中的双方括号表达式中,如果打算比较为整数,则应使用算术二元运算符。

请注意,您的busybox版本似乎使用ash,这不是bash。 Ash是“Almquist shell”,是80年代后期写成的比POSIX更早的POSIX shell。 Ash是FreeBSD中的/bin/sh的基础,除了在嵌入式系统(因此busybox)中比bash更受欢迎之外,由于其体积较小。

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