Por que preciso colocar “do” na mesma linha que “for”?

27

1. Resumo

Eu não entendo, por que preciso E010 regra bashate .

2. Detalhes

Eu uso bashate para linting .sh files. Regra E010:

do not on the same line as for

for bashate:

  • Correto:

    #!/bin/bash
    for f in bash/*.sh; do
        sashacommand "$f"
    done
    
  • Erro:

    #!/bin/bash
    for f in bash/*.sh
        do sashacommand "$f"
    done
    

Existe algum argumento válido, por que eu preciso de for e do na mesma linha?

3. Não é útil

Não consigo encontrar uma resposta para minha pergunta em:

  1. Google
  2. Artigos sobre as melhores práticas de codificação ( exemplo )
  3. documentação do bashate . Eu acho somente :

    A set of rules that help keep things consistent in control blocks. These are ignored on long lines that have a continuation, because unrolling that is kind of “interesting”

por Саша Черных 13.05.2018 / 09:23

5 respostas

58

Sintacticamente, os dois fragmentos de código a seguir estão corretos e equivalentes:

for f in bash/*.sh; do
    sashacommand "$f"
done
for f in bash/*.sh
    do sashacommand "$f"
done

O último poderia possivelmente ser considerado mais difícil de ler, pois do ofusca ligeiramente o comando no corpo do loop. Se o loop contiver vários comandos e o próximo comando estiver em uma nova linha, a ofuscação será destacada ainda mais:

for f in *
    do cmd1
    cmd2
done

... mas sinalizar isso como um "erro" é IMHO a opinião pessoal de alguém em vez de uma verdade objetiva.

Em geral, quase qualquer ; pode ser substituído por uma nova linha. Ambos ; e newline são terminadores de comando. do é uma palavra-chave que significa "aqui segue o que precisa ser feito (neste for loop)".

for f in *; do ...; done

é o mesmo que

for f in *
do
   ...
done

e como

for f in *; do
   ...
done

O motivo para usar um sobre o outro é a legibilidade e as convenções de estilo local / pessoal.

Opinião pessoal:

Em cabeçalhos de loop muito longos , acho que pode fazer sentido colocar do em uma nova linha, como em

for i in animals people houses thoughts basketballs bees
do
    ...
done

ou

for i in        \
    animals     \
    people      \
    houses      \
    thoughts    \
    basketballs \
    bees
do
    ...
done

O mesmo vale para a declaração then in if .

Mas, novamente, isso se resume às preferências de estilo pessoal ou a qualquer estilo de codificação que o time / projeto esteja usando.

    
por 13.05.2018 / 09:32
27

Observe o que está escrito no topo da página:

bashate: A pep8 equivalent for bash scripts

PEP8 é o Guia de Estilo do Código Python. Enquanto o pessoal do Python parece levar muito a sério seus problemas de estilo [carece de fontes?] , é apenas isso, um guia. Poderíamos criar upsides para colocar o do na mesma linha que o for e para colocá-lo em uma linha própria.

É a mesma discussão de onde colocar o { no código C ao iniciar um bloco if ou while (ou algo semelhante).

Algumas linhas abaixo na documentação, há outra regra interessante:

E020: Function declaration not in format ^function name {$

Assumo que o ponto aqui é que o autor desse guia de estilo acha que usar a palavra-chave function é necessário para o leitor reconhecer uma declaração de função. No entanto, function foo é uma maneira não padrão de definir uma função: a maneira padrão é foo() . A única diferença entre os dois (no Bash) é que o outro é mais difícil de portar para um shell padrão, como /bin/sh no Debian ou Ubuntu.

Então, eu sugiro pegar qualquer um desses guias de estilo com um grão de sal ou três, e decidir por si mesmo qual é o melhor estilo. Um bom verificador de estilo permite desabilitar algumas verificações (o bashate tem bashate -i E010,E011 para ignorar essas duas verificações). Um excelente verificador de estilo permitiria que você modificasse os testes, por ex. para verificar o oposto de E020, aqui.

    
por 13.05.2018 / 10:59
11

TL; DR: Você não precisa. É apenas a opinião de um cara.

Como muitos outros, venho escrevendo for loops assim há décadas:

for F in arg1 arg2 arg*
do
    somecommand "$F"
done

Esse layout destaca o fato de que do ... done circunda o corpo do loop, como chaves em linguagens semelhantes a C, e permite que novas linhas separem os componentes da construção de loop.

É claro que existem guerras religiosas sobre onde colocar as chaves também, então você pode dizer que o júri ainda está fora desta. IMHO, isso é claramente como isso foi projetado para funcionar; Bourne gostava de delimitadores combinados, cf. if ... fi , case ... esac e a necessidade de um ponto-e-vírgula na versão mais curta revelam que você está tornando-a mais curta do que o originalmente projetado. Nada de errado com isso; avanços tecnológicos e muitas coisas que antes pareciam ser uma boa ideia agora são desaprovadas, como goto . Mas até que toda a comunidade de scripts de shell adote as preferências dos bashate author (s), você não precisa fazer nada.

    
por 13.05.2018 / 16:47
3

Estou surpreso que ninguém tenha mencionado essa sintaxe válida e portátil ainda:

set alfa bravo charlie
for q do
  echo "$q"
done

Observe cuidadosamente que for e do estão na mesma linha, sem ponto e vírgula. Resultado:

alfa
bravo
charlie
    
por 14.05.2018 / 00:04
3

Várias boas respostas aqui. Sempre pegue guias de estilo com um grão de sal, e IMHO e experiência, seja sempre tão leve a moderadamente preocupado com qualquer comunidade que esteja repleta de dogmas excessivos quando se trata de estilo. É quase como se eles achassem que, quando FINALMENTE conseguirem o último que eu pontilhei, e que o último T cruzou, então o software funcionará. Às vezes é preciso mais do que um estilo perfeito para remover bugs ...

Quando comecei a aprender shell, a maioria dos scripts e tutes usavam o formato de ponto-e-vírgula em linha

for i in "$@"; do
    stuff
done

mas porque eu era inexperiente, eu tive um pouco de dificuldade em identificar o; e fazer - ambos essenciais para confirmar a correção sintática. Então eu preferi fazer a próxima linha sozinha. Eu não faço mais isso (trocadilho intencional)

Além disso, o comando 'while' é um excelente candidato para um pequeno truque:

while prep1; prep2; condition; do
    stuff
done

mas quando os comandos prep são um pouco volumosos e / ou a condição é complexa, é melhor formatada como

while
    prep1
    prep2
    condition
do
    stuff
done

e, em seguida, acrescentar o fazer como "; do" é positivamente fugly.

Você pode até ficar mais intenso do que isso:

while
    if con1; then
      cond2
    elif cond3; then
      cond4
    elif cond5; then
      cond6
    else
      cond7
    fi
do
    stuff
done

porque toda afirmação é uma expressão. Observe como os dois estilos são usados oportunisticamente. Mantê-lo limpo e é bastante legível. Compacto ou contorcê-lo em nome do estilo ou "economizando espaço" e se torna uma bagunça horrível.

Então! Dados os estilos bastante barrocos dos shell scripts em geral, qualquer coisa que vise aumentar a clareza e facilitar o acesso visual a símbolos significativos é sempre uma coisa boa.

O formulário onde 'do' é escrito em linha com o comando é doce quando você tem um pequeno comando - não acho o 'do' visualmente oculto, nem o comando interno está realmente obscurecido:

for i in whatever
  do stuff
done

Eu acho isso muito agradável de se olhar, e ele tem análogos com while, if e case:

while condition
  do stuff
end

if condition
  then stuff1
  else stuff2
fi

case $blah in
  a) stuff1;;
  b) stuff2;;
  c) stuff3;;
  *) stuffInfinity;;
esac

Clareza e limpeza geral é tudo o que Codd * pede de você.

* Edgar F. Codd, pai da teoria de banco de dados relacional.

    
por 15.05.2018 / 02:35