Por que não há um ;
caractere após do
em loops de shell quando escrito em uma única linha?
Aqui está o que quero dizer. Quando escrito em várias linhas, um for
loop se parece com:
$ for i in $(jot 2)
> do
> echo $i
> done
E em uma única linha:
$ for i in $(jot 2); do echo $i; done
Todas as linhas recolhidas recebem um ;
após elas , exceto a do
linha, e se você incluir o ;
, é um erro. Alguém provavelmente muito mais esperto do que eu decidiu que essa era a coisa certa a fazer por um motivo, mas não consigo descobrir qual é o motivo. Parece-me inconsistente.
O mesmo com while
loops também.
$ while something
> do
> anotherthing
> done
$ while something; do anotherthing; done
Essa é a sintaxe do comando. Veja Comandos Compostos
Observe especificamente:
do commands
A maioria das pessoas coloca o
do
ecommands
em uma linha separada para facilitar a leitura, mas não é necessário, você pode escrever:Eu sei que esta pergunta é especificamente sobre o shell e eu vinculei ao manual do bash. Não está escrito dessa maneira no manual do shell, mas está escrito dessa maneira em um artigo escrito por Stephen Bourne para a revista byte.
Stephen diz:
Não sei qual é o motivo original dessa sintaxe, mas vamos considerar o fato de que os
while
loops podem receber vários comandos na seção de condição, por exemploAqui, a
do
palavra-chave é necessária para diferenciar a seção de condição e o corpo principal do loop.do
é uma palavra-chave comowhile
,if
ethen
(edone
), e parece estar de acordo com as outras que não requer um ponto e vírgula ou uma nova linha depois, mas aparece imediatamente antes de um comando.A alternativa (generalizada para
if
ewhile
) ficaria um pouco feia, precisaríamos escrever, por exemplo,A sintaxe dos
for
loops é semelhante.A sintaxe do shell é baseada em prefixo. Possui cláusulas introduzidas por palavras-chave especiais. Certas cláusulas têm que andar juntas.
Um
while
loop é composto por um ou mais comandos de teste:e por um ou mais comandos do corpo:
Algo tem que dizer ao shell que um loop while começa. Esse é o propósito da
while
palavra:Mas então, as coisas são ambíguas. Qual comando é o início do corpo? Algo tem que indicar isso, e é isso que o
do
prefixo faz:e, finalmente, algo deve indicar que o último corpo foi visto; uma palavra-chave especial
done
faz isso.Essas palavras-chave do shell não exigem separação por ponto e vírgula, mesmo na mesma linha. Por exemplo, se você fechar vários loops aninhados, poderá ter apenas
done done done ...
.Em vez disso, o ponto e vírgula está entre
... test ; body ...
se eles estiverem na mesma linha. Esse ponto e vírgula é entendido como um terminador: ele pertence aotest
. Portanto, se umado
palavra-chave for inserida entre eles, ela deverá ficar entre o ponto e vírgula ebody
. Se estivesse do outro lado do ponto e vírgula, seria incorporado incorretamente natest
sintaxe do comando, em vez de ser colocado entre os comandos.A sintaxe do shell foi originalmente projetada por Stephen Bourne e é inspirada em Algol . Bourne amava tanto o Algol que usou muitas macros C no código-fonte do shell para fazer C parecer Algol. Você pode navegar pelas fontes shell datadas de 1979 da Versão 7 do Unix . As macros estão em
mac.h
, e são usadas em todos os lugares. Por exemploif
, as instruções são renderizadas comoIF
...ELSE
...ELIF
...FI
.Eu diria que
do
não é particularmente especial aqui. Você recebe um erro porque;
não pode iniciar uma lista de comandos. Se tivesse, o primeiro comando estaria vazio, e a gramática não permite comandos vazios (atribuições de variáveis ou redirecionamentos sem comando, sim, mas absolutamente nada, não). Isso é verdade em qualquer número de lugares, onde quer que uma lista de comandos seja esperada:Até:
Em todos esses lugares, uma lista de comandos é esperada e, portanto, uma entrelinha
;
é inesperada.A sintaxe é:
Qualquer uma das novas linhas, seja na lista de comandos ou antes de "do" ou "done", pode ser substituída por um ";".
Uma nova linha (mas não um ";") é permitida após o "do" e antes do "in", apenas para tornar as coisas mais bonitas, mas não faria sentido exigir uma nova linha lá.
if
é semelhante com suas palavras-chave: isso é bastante legível quando os comandos são curtos:Resposta curta, porque isso é especificado pela gramática do shell POSIX . Qualquer coisa entre
do
edone
é considerado um grupo de instruções, enquanto;
é separador sequencial:Além disso, se
;
fosse necessário, o padrão indicaria isso explicitamente e incluiriasequential_sep
depois deDo
.Porque do é uma palavra-chave e o que a segue são essencialmente parâmetros. O interpretador Bash sabe que mais se segue. É semelhante a como não há ';' seguindo o i no comando for. Você pode realmente adicionar uma nova linha após o i for e digitar o resto em uma nova linha e funcionará bem.