A

A

当取消引用 中的变量时bash,必须使用$符号。尽管如此,以下内容似乎运行良好:

x=5
[[ x -gt 2 ]]

有人能解释一下吗?

编辑:(更多信息)

我的意思是 [[ ]] 命令如何以及为什么在没有 $ 符号的情况下取消引用我的变量 x 。是的,如果 x=1,则该语句被评估为 false(返回状态 1)

答案1

原因是-eq强制对参数进行算术评估。

算术运算符:-eq-gt-lt-ge和a 内部(在 ksh、zsh 和 bash 中)意味着像 C 语言中-le一样自动扩展变量名,不需要前导。-ne[[ ]]$

  • 为了确认这一点,我们必须查看 bash 源代码。说明书上没有提供直接的确认。

    算术运算符的处理内部test.c属于这个函数:

    arithcomp (s, t, op, flags)
    

    其中st都是操作数。操作数被传递给该函数:

    l = evalexp (s, &expok);
    r = evalexp (t, &expok);
    

    该函数evalexp在 内部定义expr.c,其中包含以下标头:

    /* expr.c -- arithmetic expression evaluation. */
    

    所以,是的,算术运算符的两边(直接)都落入算术表达式求值中。直接,没有但是,没有如果。


在实践中,:

 $ x=3

这两个都失败了:

 $ [[ x = 4 ]] && echo yes || echo no
 no

 $ [[ x = 3 ]] && echo yes || echo no
 no

这是正确的,x没有被扩展并且x不等于数字。

然而:

 $ [[ x -eq 3 ]] && echo yes || echo no
 yes

 $ [[ x -eq 4 ]] && echo yes || echo no
 no

名为的变量x被扩展(即使没有 $)。

在 zsh 或 bash 中不会发生这种情况[…](在 ksh 中会发生)。


这与 a 内发生的情况相同$((…))

 $ echo $(( x + 7 ))
 10

并且,请理解这是(非常)递归的(除了 dash 和 yash):

 $ a=b b=c c=d d=e e=f f=3
 $ echo "$(( a + 7 ))" 
 10

A

答案2

数值比较-eq-gt-lt-ge-le和的操作数-ne被视为算术表达式。由于一些限制,它们仍然需要是单壳单词。

算术表达式中变量名的行为描述于壳算术:

允许 Shell 变量作为操作数;参数扩展在表达式求值之前执行。在表达式中,shell 变量也可以通过名称引用,而不使用参数扩展语法。当通过名称引用而不使用参数扩展语法时,为 null 或未设置的 shell 变量的计算结果为 0。

并且:

变量的值在被引用时被计算为算术表达式

但我实际上找不到文档中所说的数字比较采用算术表达式的部分。中没有描述条件结构[[,也没有描述在Bash 条件表达式

但是,通过实验,它似乎按照上面所说的那样工作。

所以,像这样的东西是有效的:

a=6
[[ a -eq 6 ]] && echo y 
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y

这也是(评估变量的值):

b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y

但事实并非如此;解析时它不是单个 shell 单词[[ .. ]],因此条件中存在语法错误:

[[ 1 + 2 + 3 -eq 6 ]] && echo y

在其他算术上下文中,表达式不需要没有空格。这将打印999, 因为括号明确地界定了索引中的算术表达式:

a[6]=999; echo ${a[1 + 2 + 3]}

另一方面,=比较是模式匹配,并且不涉及算术,也不涉及算术上下文中完成的自动变量扩展(条件构造):

==使用and运算符时!=,运算符右侧的字符串被视为模式,并根据模式匹配中描述的规则进行匹配,就像启用了 extglob shell 选项一样。运算=符与 相同==

所以这是错误的,因为字符串明显不同:

[[ "1 + 2 + 3" = 6 ]] 

即使数值相同,也是如此:

[[ 6 = 06 ]] 

在这里,字符串 (x6) 也进行了比较,它们是不同的:

x=6
[[ x = 6 ]]

不过,这会扩展变量,所以这是真的:

x=6
[[ $x = 6 ]]

答案3

是的,您的观察是正确的,变量扩展是在双括号下的表达式上执行的[[ ]],因此您不需要放在$变量名称前面。

手册中明确指出了这一点bash

[[ 表达 ]]

(...) 不对 [[ 和 ]] 之间的单词执行分词和路径名扩展;执行波形符扩展、参数和变量扩展、算术扩展、命令替换、进程替换和引号删除。

请注意,这不是单括号版本的情况[ ],因为[它不是 shell 关键字(语法),而是一个命令(在 bash 中它是内置的,其他 shell 可以使用外部的、内联的来测试)。

相关内容