Gue*_*est 13 bash bash-expansion
取消引用中的变量时bash
,必须使用$
符号。尽管如此,以下似乎工作得很好:
x=5
[[ x -gt 2 ]]
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下吗?
编辑:(更多信息)
我的意思是 [[ ]] 命令如何以及为什么取消引用我的变量 x 没有 $ 符号。是的,如果 x=1,则该语句被评估为 false(返回状态 1)
原因是-eq
强制对参数进行算术评估。
算术运算符:-eq
, -gt
, -lt
, -ge
, -le
and -ne
inside a [[ ]]
(在 ksh、zsh 和 bash 中)意味着像在 c 语言中一样自动扩展变量名,不需要前导$
.
为了确认,我们必须查看 bash 源代码。该手册不提供直接确认。
test.c
算术运算符里面的处理落入这个函数:
arithcomp (s, t, op, flags)
Run Code Online (Sandbox Code Playgroud)
wheres
和t
都是操作数。操作数交给这个函数:
l = evalexp (s, &expok);
r = evalexp (t, &expok);
Run Code Online (Sandbox Code Playgroud)
该函数evalexp
在内部定义expr.c
,它具有以下标头:
/* expr.c -- arithmetic expression evaluation. */
Run Code Online (Sandbox Code Playgroud)
所以,是的,算术运算符的两边都(直接)陷入算术表达式评估。直接,没有但是,没有如果。
在实践中,与:
$ x=3
Run Code Online (Sandbox Code Playgroud)
这两个都失败了:
$ [[ x = 4 ]] && echo yes || echo no
no
$ [[ x = 3 ]] && echo yes || echo no
no
Run Code Online (Sandbox Code Playgroud)
这是正确的,x
没有被扩展并且x
不等于一个数字。
然而:
$ [[ x -eq 3 ]] && echo yes || echo no
yes
$ [[ x -eq 4 ]] && echo yes || echo no
no
Run Code Online (Sandbox Code Playgroud)
命名的变量x
被扩展(即使没有 $)。
[…]
在 zsh 或 bash中不会发生这种情况(在 ksh 中会发生)。
这与 a 中发生的情况相同$((…))
:
$ echo $(( x + 7 ))
10
Run Code Online (Sandbox Code Playgroud)
并且,请理解这是(非常)递归的(dash 和 yash 除外):
$ a=b b=c c=d d=e e=f f=3
$ echo "$(( a + 7 ))"
10
Run Code Online (Sandbox Code Playgroud)
而且相当危险:
$ x='a[$(date -u)]'
$ [[ x -eq 3 ]] && echo yes || echo no
bash: Tue Dec 3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec 3 23:18:19 UTC 2018")
Run Code Online (Sandbox Code Playgroud)
可以轻松避免语法错误:
$ a=3; x='a[$(date -u >/dev/tty; echo 0)]'
$ [[ x -eq 3 ]] && echo yes || echo no
Tue Dec 4 09:02:06 UTC 2018
yes
Run Code Online (Sandbox Code Playgroud)
俗话说:净化你的输入
$ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
no
Run Code Online (Sandbox Code Playgroud)
结束
(旧的)外部/usr/bin/test
(不是内置的test
)和更旧的和外部的expr
都不扩展表达式仅整数(显然,只有十进制整数):
$ /usr/bin/test "x" -eq 3
/usr/bin/test: invalid integer ‘x’
$ expr x + 3
expr: non-integer argument
Run Code Online (Sandbox Code Playgroud)
数值比较的操作数-eq
,-gt
,-lt
,-ge
,-le
和-ne
被作为算术表达式。有一些限制,它们仍然需要是单壳词。
Shell Arithmetic 中描述了算术表达式中变量名称的行为:
允许外壳变量作为操作数;在计算表达式之前执行参数扩展。在表达式中,shell 变量也可以通过名称引用而不使用参数扩展语法。在不使用参数扩展语法的情况下按名称引用时,为 null 或未设置的 shell 变量的计算结果为 0。
并且:
变量的值在被引用时作为算术表达式求值
但我实际上找不到文档中说数字比较采用算术表达式的部分。这不是在描述的条件结构下[[
,也不是在描述猛砸条件表达式。
但是,通过实验,它似乎像上面所说的那样工作。
所以,像这样的东西有效:
a=6
[[ a -eq 6 ]] && echo y
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y
Run Code Online (Sandbox Code Playgroud)
这也是(评估变量的值):
b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y
Run Code Online (Sandbox Code Playgroud)
但这不是;[[ .. ]]
解析时它不是单个 shell 词,因此条件中存在语法错误:
[[ 1 + 2 + 3 -eq 6 ]] && echo y
Run Code Online (Sandbox Code Playgroud)
在其他算术上下文中,表达式不需要没有空格。这将打印999
,因为括号明确界定了索引中的算术表达式:
a[6]=999; echo ${a[1 + 2 + 3]}
Run Code Online (Sandbox Code Playgroud)
另一方面,=
比较是模式匹配,不涉及算术,也不涉及算术上下文(条件构造)中完成的自动变量扩展:
使用
==
and!=
运算符时,运算符右侧的字符串被视为一个模式,并根据以下模式匹配中描述的规则进行匹配,就好像启用了 extglob shell 选项一样。的=
操作者是相同的==
。
所以这是错误的,因为字符串明显不同:
[[ "1 + 2 + 3" = 6 ]]
Run Code Online (Sandbox Code Playgroud)
即使数值相同,也是如此:
[[ 6 = 06 ]]
Run Code Online (Sandbox Code Playgroud)
在这里,也比较了字符串(x
和6
),它们是不同的:
x=6
[[ x = 6 ]]
Run Code Online (Sandbox Code Playgroud)
但是,这会扩展变量,所以这是真的:
x=6
[[ $x = 6 ]]
Run Code Online (Sandbox Code Playgroud)
是的,您的观察是正确的,变量扩展是在双括号下的表达式上执行的[[ ]]
,因此您不需要放在$
变量名称前面。
手册中明确指出了这一点bash
:
[[ 表达 ]]
(...) 不对 [[ 和 ]] 之间的单词执行分词和路径名扩展;执行波形符扩展、参数和变量扩展、算术扩展、命令替换、进程替换和引号删除。
请注意,这不是单括号版本的情况[ ]
,因为[
它不是 shell 关键字(语法),而是一个命令(在 bash 中它是内置的,其他 shell 可以使用外部的、内联的来测试)。
归档时间: |
|
查看次数: |
990 次 |
最近记录: |