Estou online ZSH_VERSION=5.9
e tenho este script que funciona como esperado:
integer count=3
while true ; do
echo $count
(( count-- ))
if (( count == 0 )) break
done
echo Finally: $count
echo ok
Ele faz a contagem regressiva de 3
até 1
e então diz: Finally: 0
e ok
.
Mas vamos substituir o do ... done
bloco por um { ... }
como este:
integer count=3
while true ; {
echo $count
(( count-- ))
if [[ $count == 0 ]] break
}
echo Finally: $count
echo ok
Não há absolutamente nenhuma mensagem de erro, mas a saída é confusa:
3
Finally: 2
ok
2
Finally: 1
ok
1
Não tenho a mínima ideia do porquê disso, exceto que o analisador tem um problema. Ou estou usando a sintaxe alternativa while-loop errada? Isso acontece quando estou em um shell recém-iniciado.
As formas alternativas dos comandos complexos são mais limitadas do que as formas padrão;
while true
não é suportado. Dos documentos :Há várias maneiras de criar uma condição 'adequadamente delimitada' sempre verdadeira. Uma opção:
A parte surpreendente é que a
while true; {...
versão do loop produz qualquer saída, em vez de gerar uma mensagem de erro. Com base em alguns testes limitados, parece que, na ausência de qualquer um dos delimitadores adequados, o analisador simplesmente adiciona tudo após owhile
até o final do script àslist
condições de. O loop resultante é provavelmente semelhante a este:Este loop tem vários comandos na condição
list
, o que é permitido pelawhile
sintaxe, mas quase nunca usado. Observe que o código de retorno do último comando na lista é o testado pelowhile
; neste caso, é umecho
que retorna com sucesso. É oif...break
que encerra este loop.Não encontrei nenhuma documentação que descreva esse comportamento aparente de 'usar tudo até eof'. Você pode ter alguma sorte perguntando aos desenvolvedores na lista de discussão do zsh se isso é intencional, um bug de análise ou uma interpretação errônea do que está acontecendo.
Editado para adicionar: Parece que houve alguma discussão relacionada a isso na lista de discussão em 2018 e 2024. Um patch para detectar quando não havia uma condição delimitada nunca foi aplicado, em grande parte porque o
zsh
analisador já imprimirá um erro nesse caso se aSHORT_LOOPS
opção não estiver definida (ela é definida por padrão):Obrigado @Gairfowl por me apontar a direção certa. O ponto e vírgula ou a nova linha simplesmente não termina uma lista , mas apenas uma sublista , após a qual mais sublistas podem seguir. Dentro de um
{ ... }
o último ponto e vírgula ou nova linha pode ser omitido, no entanto.Quando o zsh analisa a
while list do list done
, as palavras reservadas do e done encerram as duas listas. Mas quando awhile true; { list }
é visto, o analisador tomatrue;
como primeira sublista,{ list }
como segunda, e todos os comandos subsequentes em linhas separadas como sublistas adicionais, também, até o EOF. Acabamos tendo uma lista maior do que o pretendido para a condição de loop, e um corpo vazio do loop. Obviamente, um corpo vazio é permitido, então eu diria que esse comportamento é intencional, no geral.Para resumir, as seguintes construções estão funcionando conforme o esperado:
Mas o seguinte NÃO está funcionando:
Ele tem o mesmo problema de "ganância" que
while true; { ... }
.