为什么ksh中的“[[”和“-e xxx”之间需要空格?

AcB*_*Bap 9 command-line syntax ksh

例如,以下命令不起作用:

if [[-e xyz]]; then echo File exists;fi
Run Code Online (Sandbox Code Playgroud)

ksh 给出以下错误

[[-e: command not found
Run Code Online (Sandbox Code Playgroud)

那是因为“[[-”不明确吗?

Ser*_*nyy 15

最简单的解释是,因为在手册中它显示为[[ expression ]]所以必须在[[andexpression和 closed之间有空间]]。但是我们当然可以尝试更深入地研究它。Shell 的语法有些复杂,并且在很大程度上依赖于“分词”的概念。特别是, ksh(1)手册指出:

shell 通过将其分解为单词来开始解析它的输入。作为字符序列的单词由不带引号的空白字符(空格、制表符和换行符)或元字符(<、>、|、;、&、(和))分隔。除了分隔单词之外,空格和制表符也被忽略,而换行符通常用于分隔命令。

因此,如手册中所述,字符序列[[-e被视为外壳词。ksh将在内置命令和特殊运算符(如forwhile)列表中查找此类命令,然后查找外部命令 - 瞧 - 没有找到,因此会出现有关未找到命令的错误消息。

在这种情况下[[也不是特殊的元字符。如果是,则-ein 部分[[-e将被视为一个 shell 词,而不是其[[自身的参数。但是,[[被描述为复合命令,并且手册说如下:

复合命令是使用以下保留字创建的——这些字只有在它们没有被引号引起来并且用作命令的第一个字时才能被识别(即,它们前面不能有参数分配或重定向):

因此,为了[[被识别为复合命令,它必须是命令或命令列表的第一个单词,根据之前对“单词”的定义,这意味着它必须用空格、制表符或换行符与其他单词隔开词/论点。


你在评论中问过:“为什么解析器不能在找到“[[”模式后立即停止,并将其视为条件命令的开始?简短的回答可能是因为 1)[语法的影响,因为它最初是一个外部命令,对于 POSIX 标准合规性,即使在今天也作为外部命令存在,2) 因为 shell 解析器是这样构建的。Shell 解析器可以识别其他非空格分隔的特殊字符: echo $((2+2))并且(echo foobar)工作得很好。也许将来当ksh开发恢复或出现分叉或克隆(如mkshpdksh)时,有人会在[[-e.

也可以看看:

  • 我认为 ksh 手册引用确实是当场的。它类似于任何其他编程语言:在 C 中,`char` 是一个关键字,但你*仍然*不能编写 `charsomeletter = 'A';` 并期望解析器在看到 `char` 后停止。 (3认同)