Answers:
最简单的解释是,因为在手册中显示为[[ expression ]]
如此,必须有之间的空间[[
和expression
闭]]
。但是我们当然可以尝试更深入地研究它。Shell的语法有些复杂,并且严重依赖“单词拆分”的概念。特别是, ksh(1)手册指出:
Shell通过将其分解为单词来开始解析其输入。单词是字符序列,由无引号的空格字符(空格,制表符和换行符)或元字符(<,>,|,;,&,(和))分隔。除了分隔单词外,空格和制表符也被忽略,而换行符通常分隔命令。
因此,如手册中所述,字符序列[[-e
被认为是一个空壳词。ksh
会在内置函数和特殊运算符(如for
或while
)的列表中查找此类命令,然后查找外部命令-和voilà-未找到,因此出现有关未找到命令的错误消息。
在这种情况下[[
,也不是特殊的元字符。如果是这样,那么其中的-e
部分[[-e
将被视为一个空壳词,而不是其[[
自身的参数。但是,[[
被描述为复合命令,并且该手册中指出以下内容:
复合命令是使用以下保留字创建的-仅在未引号且将它们用作命令的第一个字的情况下,这些字才被识别(即,它们不能以参数赋值或重定向开头):
因此,为了[[
被识别为复合命令,它必须是命令或命令列表的第一个单词,根据先前对“单词”的定义,这意味着它必须用空格,制表符或换行符分隔单词/参数。
您已经在注释中提出了疑问:“为什么解析器一旦找到“ [[”模式并将其视为条件命令的开始,就无法停止?” 简短的答案可能是因为1)[
语法的影响,因为它最初是一个外部命令,并且对于POSIX标准,即使在今天,依从性仍然作为外部命令存在;以及2)因为shell解析器是这样构建的。Shell解析器可以识别其他非空格分隔的特殊字符: echo $((2+2))
并且(echo foobar)
工作得很好。也许将来ksh
开发恢复时,或者似乎出现了fork或克隆(如mksh
或pdksh
)时,有人会在中实现无空间语法[[-e
。
[[
称为“保留字”(请参阅Shell命令语言的2.9节)。根据POSIX的定义,保留字必须用空格分隔。相比之下,(
是运算符,而标准在2.9节中指出:“表示形式包括在某些不需要<blank>
s的地方(当标记之一是运算符时)标记之间的间距”。请参阅相关讨论: POSIX Shell语法:为什么Brace组需要第一个空格而Subshell不需要?char
是一个关键字,但是您仍然无法编写代码,charsomeletter = 'A';
并且希望解析器在看到之后会停止char
。
i--<=++j
,编译器毫无疑问地将其解析为i -- <= ++ j
。
_
)。Ksh具有(
作为运算符,并(echo hello)
解析为( echo hello )
。它if
,{
,[[
,等关键字,和ifx
,{x
和[[x
是每一个令牌-怎么样charsomeletter
是一种C标记。相比之下,(x
ksh中未加引号的是两个令牌-就像i--
C中的两个令牌一样。Bourne样式的shell(如ksh)和C之间在概念上甚至意味着要成为运算符也不同。但是Peter A. Schneider指出真正的词汇相似性。
需要注意的重要一点是这[
是一个命令,[[
bash和ksh中的shell关键字基于[
。
[[
的用法与相似[
。有时,您甚至可以替换为[
]
,[[
]]
而无需改变行为。使用[
和任何命令一样,该命令及其参数之间必须有一个空格。同样适用于[[
。
我们曾经只有/usr/bin/[
。现在,大多数shell都是[
为了提高效率而内置的-但语法是相同的。在提供的外壳中[[
,它可以作为通用的替代品[
。
这是[
bash中的描述:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
因此[
等于test
(除了在最后期望]
参数之外)。help test
将提供更多细节。您可以将此与进行比较help [[
。
外部命令[
(man \[
)也有一个手册页。
如果是
if [[-e
[
没有[[
命令。完整的词[[-e
是。if [[-e
使其成为对/错的测试。那么命令是否[[-e
存在? 那是因为“ [[-”不明确吗?
是。或者没有。[[-e
就是这样:shell无法理解任何内容,因此假定它是自己的命令。;-)
[[-e
是一个可能有效的(如果看起来很奇怪)命令名称。
该空间是分隔符,是必需的。如您所见shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(ksh和bash都支持,[[
并且没有空格就无法工作。Shellcheck会使用包含该错误行的类似的ksh和bash脚本准确地提供该输出。)
为什么需要分隔符与标记和词典有关。
ksh
在问题中询问了有关shell的问题。巴什借用[[
操作者ksh
和在这个问题上他们的行为是相同的,但有一些之间的差异显著我会谨慎的假设ksh
和bash
行为和内部结构。那仅仅是因为shellcheck在bash脚本上工作,它不一定是ksh脚本的合适工具。接近不同炮弹时要记住的事情
[[
内置规则时表现出机会。我绝不推断这ksh
是一个shellcheck
可以发现错误的外壳。我希望其他人会喜欢ksh
并且bash
是两个不同的解释器。谢谢你提到那件事。还值得注意的[[
是内置的bash,而[
外部命令则是。
[
它也是bash的内置功能:) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html但是您相距不远- [
或test
需要作为外部命令。在最初的Bourne shell时代[
,实际上是一个外部命令,并且/usr/bin/[
由于POSIX要求它是一个外部命令,因此如今仍然存在,它是pubs.opengroup.org/onlinepubs/009695399/utilities/test.html POSIX几乎不需要内置pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html 内置功能[
是为了提高效率
ksh
; 使用hashbang或-s ksh
。顺便说一句,KSH和bash有[[
“中建”,但它是一个关键词,不像[
,这是一个shell内建。(ksh :; whence -v [ [[
bash type [ [[
:)内置命令和外部命令在语法上相似。一种方式[[
不同于[
的是,[[
抑制了它的参数,它不能作为一个内置了一些扩展-就像{
不能做分组是它内置的。这可能就是为什么{x
(或[[x
)作为一个令牌感到奇怪的原因。我认为说内置函数和关键字在词法上相似但在语法上不相似是正确的。@SergiyKolodyazhnyy
[[
可以是外部命令!也就是说,它可能是一个程序,而不是外壳程序直接支持的某些语法。支持无空间语法是可能的,ksh
但在具有外部系统的系统上可能会失败,[[
因此出于兼容性原因,最好保留所需的空间。
由于[[-e
可以参与shell扩展(它可以像
echo [[-e]*
为了列出所有以“。” [
和“。” 之间的字母开头的文件e
,如果[
和]
是特殊字符不参与正常的空白字分割,那将是一团糟。
[[
是一个关键字 -可能是外壳的解析树要求关键字必须由空格划定