今天在编写一些 bash 脚本时,我发现了一些令人惊讶的事情。我把它归结为这个最小的例子。
[[ a>b ]]; echo $?
根据我的理解,因为 两边没有空格>
,所以这里应该是检测字符串是否a>b
不为空,应该返回错误码0
。但是,上面的命令1
在我测试的两个 bash 版本中都有响应(详情如下)。
我还使用旧的“good”test
命令进行了测试,
[ a>b ]; echo $?
echos 0
(测试字符串a
不为空并b
在我当前的工作目录中创建一个空文件,显然>b
被视为重定向,这是可以理解的)。
然后我又尝试了一些其他的东西
[[ b>a ]]; echo $?
echos0
并且没有创建文件。[[ b<a ]]; echo $?
echos1
并且没有创建文件。[[ a<b ]]; echo $?
echos0
并且没有创建文件。[ b>a ]; echo $?
回声0
并创建一个空文件a
。[ b<a ]; echo $?
报告由于该错误而丢失文件a
和回显的错误。1
[ a<b ]; echo $?
报告由于该错误而丢失文件b
和回显的错误。1
[[ a=b ]]; echo $?
echos0
因为它正在测试字符串是否a=b
如我预期的那样非空。[ a=b ]; echo $?
0
出于同样的原因回声。[[ a==b ]]; echo $?
0
出于同样的原因回声。[ a==b ]; echo $?
0
出于同样的原因回声。[[ a!=a ]]; echo $?
并且[ a!=a ]; echo $?
都回显0
(预期)
因此,在条件表达式中似乎只有<
and周围的空格>
可以省略,但 or =
or ==
if!=
的目的是进行字符串比较。但是为什么要这样设计呢?这也可能是我的遗漏,但这似乎没有在 bash 手册的任何地方记录。
我最初的问题是尝试使用>
未转义作为条件表达式 ( ) 中模式的一部分[[ ... ]]
。我最初认为只要我不用>
空格包围我就应该能够毫无问题地使用它,因为它没有意义(并且经过一些测试证明是不可能的)在条件内进行重定向表达要么。
然而事实并非如此。当然,简单的解决方案就是转义>
并改为编写\>
,但我不明白为什么需要它。
这是我用于测试的 bash 版本,
GNU bash, version 5.2.2(1)-release (aarch64-unknown-linux-android)
和
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
我的实验是在 下进行的env -i bash --norc --noprofile
。
这归结为
&
,;
,(
,|
,<
,>
, tab 等字符是shell 语法中的元字符。它们形成自己的标记(或者可以组合成更多标记,例如;;
,|&
,||
...)。[
这与,{
,!
¹ 等字符不同-
,=
它们类似于字母 ² 和数字。在 Korn shell 的构造内部
[[...]]
,shell 理解一种单独的微语言,但它遵循与外部大致相同的标记化规则。出于同样的原因,在 之外
[[...]]
,您可以执行以下操作:并且不必写它:
甚至像
if((1))then<file&&(uname)fi
.在这里,您可以:
as
(
、>
和|
是)
shell 元字符。元字符必须用引号引起来(无论是用
'...'
,"..."
,\
,$'...'
...)才能按字面意思理解。[[x]]
不会工作,因为 shell 只能看到一个[[x]]
标记。甚至无法识别[[
启动该构造的关键字。与微语言中的不同,是单个标记,因此与 的解释相同。[[...]]
[[ a==b ]]
[[ a == b ]]
[[...]]
a==b
[[ -n 'a==b' ]]
[
本身只是一个普通命令,所以它的解析方式与另一个命令相同。[
以a
and as 参数运行]
,其输出重定向到b
, same as[ a ] > b
, just likeecho a>b ]
is the same asecho a ] > b
or>b echo a ]
。请注意,它的内部(也来自 ksh)不同,
((...))
它也带有自己的类 C 微语言,但这次标记化规则不同。例如,您可以编写((var=123+1))
or((a==b))
并且不需要((var = 123 + 1))
or((a == b))
。¹
{
涉及大括号扩展,也是 shell 保留字,但在标记化之后处理,[
虽然在解析分配时涉及标记化。a[1 + 1]=foo
在 bash 或 ksh(不是 zsh)中被解析为一个赋值词,而不是作为参数a[1
运行。是一个保留字,如,但也涉及历史扩展,尽管它仅用于 shell 的交互式调用。+
1]=foo
!
{
² 请注意,
-
某些运算符中包含字母和,[[...]]
例如-nt
,-eq
,-lt
...