为什么“if [[ ... ]] then”(没有分号或换行符)在 ksh 中有效,但在 bash 中无效?

Men*_*hem 4 bash shell ksh

我注意到 KSH 和 Bash 之间的差异,并且我正在寻找记录该差异的位置,或者可能确认其中一个是错误。

在 Korn Shell 中(在 KSH88 和 KSH93 上看到),此命令运行良好,并打印结果“yes”:

if [[ -z "" ]] then echo yes ; fi       # Note no ';' after the ']]'
Run Code Online (Sandbox Code Playgroud)

在 Bash 中,我得到一个syntax error near unexpected token 'then'.

仅当我使用双括号时才会出现此行为。如果我使用单括号形式的条件表达式,KSH 和 Bash 都会给我一个没有分号的语法错误,但会抱怨 而fi不是then.

这是一个错误还是一个功能?在 ksh 或 Bash 中?我注意到 Bash 和 ksh 的手册页的 语法略有不同if,但这种差异似乎不适用于这种情况。


编辑:bash有人(@jp48)指出了和手册页之间语法定义的显着差异ksh。然而,查看与AST源代码匹配的 Solaris (11.3)手册页,语法为:

if list ;then list [ ;elif list ;then list ] ... [ ;else list ] ;fi
Run Code Online (Sandbox Code Playgroud)

它与 Bash 手册页的区别在于分号的位置(而不是存在)在 // 之前,elifelse不是filist:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi
Run Code Online (Sandbox Code Playgroud)

不带分号的备用语法来自 ksh 的公共域版本(可能是 PDksh),而不是“官方”ksh 版本。

jp4*_*p48 5

TL;DR:根据ksh 手册页,这不是一个错误。


[和之间的主要区别[[在于,它[是一个关键字,并且[[是两个 shell 中的内置函数。请注意,出于性能原因,永远不会使用“后备可执行文件” /bin/[(本质上是/bin/test),但如果我们假装执行了此命令,则可以更好地理解接下来的内容。

值得注意的是,这]]也是一个关键字,但]只是传递给[/ 的参数test

这是一些证明(两个 shell 中的输出几乎相同):

$ type [[
[[ is a shell keyword
$ type ]]
]] is a shell keyword
$ type [
[ is a shell builtin
$ type ]
***: not found
Run Code Online (Sandbox Code Playgroud)

解释完这一点后,让我们看看您的示例中会发生什么。

根据此手册页, bash 的行为符合预期(即它需要;

if list; then list; [ elif list; then list; ] ... [ else list; ] fi
Run Code Online (Sandbox Code Playgroud)

然后让我们关注 ksh,作为参考,我将使用 FreeBSD 的手册页

ksh中的语法if如下

if list then list [elif list then list] ... [else list] fi
Run Code Online (Sandbox Code Playgroud)

以及 ksh 中的列表:

必须以分号、换行符或(语法正确的)保留字结尾

因此,[...]without;不是一个有效的列表(请记住,最后一个]不是关键字也不是内置的,而是传递给 的“参数” [)。

[[...]]是一个有效列表,因为]]是一个语法正确的保留字

总之,这不是一个错误,因为它遵循规范;;当然,不使用(或换行符)并不是最佳实践,而且可能不符合 POSIX 标准。