我正在使用ZSH_VERSION=5.9
并且有这个脚本,它可以按预期工作:
integer count=3
while true ; do
echo $count
(( count-- ))
if (( count == 0 )) break
done
echo Finally: $count
echo ok
3
它从到倒数1
,然后说:Finally: 0
和ok
。
但是让我们do ... done
用{ ... }
这样的方式替换该块:
integer count=3
while true ; {
echo $count
(( count-- ))
if [[ $count == 0 ]] break
}
echo Finally: $count
echo ok
绝对没有错误消息,但输出令人困惑:
3
Finally: 2
ok
2
Finally: 1
ok
1
我完全不知道为什么会这样,除非解析器有问题。还是我错误地使用了替代的 while 循环语法?当我在刚启动的 shell 中时会发生这种情况。
复杂命令的替代形式比标准形式更受限制;
while true
不受支持。摘自文档:有多种方法可以创建“适当分隔”的始终为真的条件。一种选择是:
令人惊讶的是,该
while true; {...
版本的循环竟然产生了任何输出,而不是生成错误消息。根据一些有限的测试,似乎在缺少任何合适的分隔符的情况下,解析器只是将while
脚本末尾之后的所有内容添加到list
条件中。结果循环可能类似于此:此循环在条件 中有多个命令
list
,这是语法允许的while
,但几乎从未使用过。请注意,列表中最后一个命令的返回代码是 测试的while
;在本例中,这是echo
成功返回的 。结束此循环的是if...break
。我还没有找到任何文档来描述这种明显的“使用所有内容直到 eof”行为。您可能会幸运地询问zsh 邮件列表中的开发人员,这是故意的、解析错误还是对正在发生的事情的误解。
编辑后添加:看起来在2018 年和2024 年的邮件列表中有一些与此相关的讨论。从未应用过用于检测何时没有分隔条件的补丁,很大程度上是因为
zsh
如果未设置该选项(默认情况下设置),解析器在这种情况下将打印错误SHORT_LOOPS
:感谢@Gairfowl 为我指明了正确的方向。分号或换行符根本不是列表的终止符,而只是子列表的终止符,之后可能会有更多子列表。
{ ... }
但是,在列表内,可以省略最后一个分号或换行符。当 zsh 解析 a 时
while list do list done
,保留字do和done终止这两个列表。但是当while true; { list }
看到 a 时,解析器将其true;
作为第一个子列表,{ list }
作为第二个子列表,并将所有后续在单独行上的命令也视为附加子列表,直到 EOF。我们最终得到的列表比循环条件预期的要长,并且循环体为空。显然,空体是允许的,所以我会说,总的来说,这种行为是故意的。综上所述,以下结构按预期运行:
但以下方法不起作用:
它与 有同样的“贪婪”问题
while true; { ... }
。