当取消引用 中的变量时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)
其中
s
和t
都是操作数。操作数被传递给该函数: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 ]]
在这里,字符串 (x
和6
) 也进行了比较,它们是不同的:
x=6
[[ x = 6 ]]
不过,这会扩展变量,所以这是真的:
x=6
[[ $x = 6 ]]
答案3
是的,您的观察是正确的,变量扩展是在双括号下的表达式上执行的[[ ]]
,因此您不需要放在$
变量名称前面。
手册中明确指出了这一点bash
:
[[ 表达 ]]
(...) 不对 [[ 和 ]] 之间的单词执行分词和路径名扩展;执行波形符扩展、参数和变量扩展、算术扩展、命令替换、进程替换和引号删除。
请注意,这不是单括号版本的情况[ ]
,因为[
它不是 shell 关键字(语法),而是一个命令(在 bash 中它是内置的,其他 shell 可以使用外部的、内联的来测试)。