我曾经相信引用字符串总是一个很好的做法,以避免让 shell 解析它。
然后我遇到了这个:
$ x='('
$ [ "$x" = '1' -a "$y" = '1' ]
bash: [: `)' expected, found 1
Run Code Online (Sandbox Code Playgroud)
试图隔离问题,得到同样的错误:
$ [ '(' = '1' -a '1' = '1' ]
bash: [: `)' expected, found 1
Run Code Online (Sandbox Code Playgroud)
我解决了这样的问题:
[ "$x" = '1' ] && [ "$y" = '1' ]
Run Code Online (Sandbox Code Playgroud)
我仍然需要知道这里发生了什么。
Nom*_*mal 25
这是一个非常模糊的极端情况,人们可能会认为测试[
内置的定义方式存在错误;但是,它确实与[
许多系统上可用的实际二进制文件的行为相匹配。据我所知,它只影响某些情况和具有匹配[
运算符(如(
、!
、=
、等)的值的变量-e
。
让我解释一下原因,以及如何在 Bash 和 POSIX shell 中解决它。
解释:
考虑以下:
x="("
[ "$x" = "(" ] && echo yes || echo no
Run Code Online (Sandbox Code Playgroud)
没问题; 以上不会产生错误,并输出yes
. 这就是我们期望东西工作的方式。'1'
如果您愿意,您可以将比较字符串更改为,以及 的值x
,它会按预期工作。
请注意,实际/usr/bin/[
二进制文件的行为方式相同。如果你运行 eg'/usr/bin/[' '(' = '(' ']'
没有错误,因为程序可以检测到参数由单个字符串比较操作组成。
错误发生时,我们并与第二表达。第二个表达式是什么并不重要,只要它是有效的。例如,
[ '1' = '1' ] && echo yes || echo no
Run Code Online (Sandbox Code Playgroud)
输出yes
,显然是一个有效的表达式;但是,如果我们将两者结合起来,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Run Code Online (Sandbox Code Playgroud)
当且仅当x
是(
或 时,Bash 拒绝该表达式!
。
如果我们要使用实际[
程序运行上述内容,即
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Run Code Online (Sandbox Code Playgroud)
该错误是可以理解的:由于 shell 进行变量替换,/usr/bin/[
二进制文件只接收参数(
=
(
-a
1
=
1
和终止]
,可以理解无法解析左括号是否开始子表达式,其中 涉及and操作。当然,将它解析为两个字符串比较是可能的,但是当应用于带有括号的子表达式的正确表达式时,像这样贪婪地这样做可能会导致问题。
实际上,问题在于 shell[
内置的行为方式相同,就好像它x
在检查表达式之前扩展了 的值一样。
(这些歧义以及其他与变量扩展相关的歧义是 Bash 实现并现在推荐使用[[ ... ]]
测试表达式的一个重要原因。)
解决方法很简单,经常在使用旧sh
shell 的脚本中看到。您添加一个“安全”字符,通常是x
,在字符串前面(两个值都被比较),以确保表达式被识别为字符串比较:
[ "x$x" = "x(" -a "x$y" = "x1" ]
Run Code Online (Sandbox Code Playgroud)
Ale*_*exP 11
[
又名test
看到:
argc: 1 2 3 4 5 6 7 8
argv: ( = 1 -a 1 = 1 ]
Run Code Online (Sandbox Code Playgroud)
test
接受括号中的子表达式;所以它认为左括号打开一个子表达式并试图解析它;解析器将=
子表达式中的第一件事视为并认为它是隐式字符串长度测试,因此很高兴;然后子表达式后面应该跟一个右括号,而是解析器找到1
而不是)
. 它抱怨。
当test
正好有三个参数,并且中间的参数是公认的运算符之一时,它将将该运算符应用于第一个和第三个参数,而无需查找括号中的子表达式。
有关完整的详细信息man bash
,请查看、搜索test expr
。
结论: 使用的解析算法test
复杂。仅使用简单的表达式并使用shell运算符!
, &&
and||
将它们组合起来。
归档时间: |
|
查看次数: |
1653 次 |
最近记录: |