Pourquoi dois-je placer «do» sur la même ligne que «for»?

28

1. Résumé

Je ne comprends pas, pourquoi ai-je besoin de la règle basate E010 .


2. Détails

J'utilise bashate pour peloter les.sh fichiers. Règle E010:

ne pas sur la même ligne que pour

for bashate:

  • Correct:

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

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

Y a-t-il des arguments valides, pourquoi ai-je besoin foret dodans la même ligne?


3. Inutile

Je ne trouve pas de réponse à ma question dans:

  1. Google
  2. Articles sur les meilleures pratiques de codage ( exemple )
  3. documentation bashate . Je ne trouve que :

    Un ensemble de règles qui aident à garder les choses cohérentes dans les blocs de contrôle. Celles-ci sont ignorées sur les longues files qui ont une suite, car dérouler c'est un peu «intéressant»

Саша Черных
la source
3
Le retrait doest certainement un peu inhabituel, mais il for ... \ndo\n<indent>body...est extrêmement courant et je l'estimerais même plus for ... ; do. Se plaint-il également de cela?
Michael Homer
20
bashateest un vérificateur de style . Les styles sont intrinsèquement subjectifs. Ne l'utilisez pas si vous n'aimez pas le style d'artibrary qu'il impose. Vous devriez plutôt envisager un vérificateur de syntaxe / bogue comme shellcheck .
meuh
@meuh, merci, j'utilise déjà ShellCheck. ma question: E010- que le style règle ou dans certains cas , j'ai besoin pour et fais dans la même ligne , non seulement par des raisons de style.
Саша Черных
10
Il n'y a jamais une obligation syntaxique d'avoir pour et faire sur la même ligne dans la coquille.
meuh
1
@ Саша Черных Ce n'est pas l'indentation en soi qui est inhabituelle, c'est l'indentation de do. Il est comme l'accolade indenter ouverture d'un ifet en ajoutant le code sur la même ligne dans une langue comme C. Un autre exemple, si python lui a permis, serait mettre la :d'un ifretrait sur la ligne suivante et en ajoutant le code sur cette même ligne. Cela va le faire différer avec des lignes supplémentaires dans le corps.
JoL

Réponses:

60

Syntaxiquement, les deux extraits de code suivants sont corrects et équivalents:

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

On pourrait peut- être dire que ce dernier est plus difficile à lire car il doobscurcit légèrement la commande dans le corps de la boucle. Si la boucle contient plusieurs commandes et que la commande suivante se trouve sur une nouvelle ligne, l'obscurcissement serait davantage mis en évidence:

for f in *
    do cmd1
    cmd2
done

... mais le signaler comme une "erreur" est l'opinion personnelle de quelqu'un à mon humble avis plutôt qu'une vérité objective.

En général, presque tous ;peuvent être remplacés par une nouvelle ligne. Les deux ;et newline sont des terminateurs de commande. doest un mot-clé qui signifie "voici ce qui doit être fait (dans cette forboucle)".

for f in *; do ...; done

est le même que

for f in *
do
   ...
done

et comme

for f in *; do
   ...
done

La raison d'utiliser l'un sur l'autre est la lisibilité et les conventions de style local / personnel.


Opinion personnelle:

Dans les en-têtes de boucle qui sont très longs , je pense qu'il peut être judicieux de mettre doune nouvelle ligne, comme dans

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

ou

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

Il en va de même pour le thendans une ifdéclaration.

Mais encore une fois, cela se résume aux préférences de style personnel ou au style de codage utilisé par l'équipe / le projet.

Kusalananda
la source
Vous dites que «Dans les en-têtes de boucle qui sont très longs, il peut être judicieux de mettre le do sur une nouvelle ligne». Pourriez-vous expliquer pourquoi? Étant donné que l'en-tête doit être suivi do, je ne vois pas pourquoi le mettre sur la ligne suivante aiderait la lisibilité.
Konrad Rudolph
3
@KonradRudolph Mon terminal a une largeur de 80 caractères. Si la liste se termine, je vais en faire un ensemble de lignes continues (comme dans mon dernier exemple), si elle se termine presque , je mettrai le do(ou then) sur une ligne seule (comme dans l'avant-dernier exemple). Tout cela dépend des préférences personnelles. Je n'aime pas les lignes trop longues, en partie parce que mon terminal ne fait "que" 80 caractères de large, et en partie parce que je pense qu'il semble désordonné. J'ai également du mal à analyser les très longues lignes pour les erreurs.
Kusalananda
1
Il semble inutile de continuer à souligner qu'il s'agit d'une opinion. bashate est un guide de style, il est donc intrinsèquement basé sur l'opinion.
Barmar
4
@Barmar, notez que la question ici utilise un phrasé comme "besoin de" et "règle", et le readme bashate appelle avoir dosur une ligne séparée une "erreur". Ce sont plutôt des phrases strictes, il ne semble la peine de souligner que, bien au contraire, le soi-disant « règle » est en fait juste une opinion subjective.
ilkkachu
2
@mtraceur D'accord, je ne remets pas en question les préférences personnelles. Mais sachez que la limite de colonne de lisibilité que vous citez ne s'applique pas au code. Cela ne s'applique qu'à la prose. Le mouvement des yeux est fondamentalement différent pour la lecture de code, donc les preuves de ces études ne sont pas applicables ici. Et en ce qui concerne l'utilisation de raisons historiques qui ne s'appliquent plus comme justification, eh bien, nous avons également utilisé les noms de fichiers 8.3 précédents.
Konrad Rudolph
28

Notez ce qu'il dit en haut de la page:

bashate: un équivalent pep8 pour les scripts bash

PEP8 est le guide de style pour le code Python. Alors que les gens de Python semblent souvent prendre très au sérieux leurs problèmes de style [citation nécessaire] , c'est juste cela, un guide. Nous pourrions trouver des avantages à la fois pour mettre le dodans la même ligne que le for, et pour le mettre sur une ligne qui lui est propre.

C'est la même discussion où mettre le {dans le code C lors du démarrage d' un ifou whilebloc (ou tel).


Quelques lignes plus bas dans la documentation, il y a une autre règle intéressante:

E020: Déclaration de fonction non au format ^function name {$

Je suppose que le point ici est que l'auteur de ce guide de style pense que l'utilisation du functionmot-clé est nécessaire pour que le lecteur reconnaisse une déclaration de fonction. Cependant, function fooest une façon non standard de définir une fonction: la manière standard est foo(). La seule différence entre les deux (dans Bash) est que l'autre est plus difficile à porter sur un shell standard, comme /bin/shdans Debian ou Ubuntu.

Donc, je suggère de prendre n'importe lequel de ces guides de style avec un grain de sel ou trois, et de décider par vous-même quel est le meilleur style. Un bon vérificateur de style permet de désactiver certaines vérifications (bashate doit bashate -i E010,E011ignorer ces deux vérifications.) Un excellent vérificateur de style vous permettrait de modifier les tests, par exemple pour vérifier l'opposé de E020, ici.

ilkkachu
la source
12

TL; DR: Vous n'en avez pas besoin. C'est juste l'opinion d'un mec.

Comme beaucoup d'autres, j'écris des forboucles comme celle-ci depuis des décennies:

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

Cette disposition met en évidence le fait que do ... donele corps de la boucle est entouré, comme les accolades dans les langages de type C, et permet aux sauts de ligne de séparer les composants de la construction de la boucle.

Bien sûr, il y a des guerres de religion pour savoir où placer les accolades, donc vous pourriez dire que le jury n'est toujours pas sur celui-ci. À mon humble avis, c'est clairement ainsi que cela a été conçu pour fonctionner; Bourne aimait les délimiteurs assortis, cf. if ... fi, case ... esacet la nécessité d'un point-virgule dans la version plus courte révèle que vous le rendez plus court que prévu. Aucun problème avec ça; les avancées technologiques et beaucoup de choses qui semblaient autrefois être une bonne idée sont maintenant mal vues, comme goto. Mais jusqu'à ce que toute la communauté des scripts shell adopte les préférences des bashateauteurs, vous n'avez rien à faire.

alexis
la source
3
Le ficorrespondant à if, et esacetc. vient de Algol 68. La seule raison pour laquelle une forboucle « s don'est pas fini par odest que odest le nom d'un utilitaire standard existant. Voir en.wikipedia.org/wiki/ALGOL_68C#Algol_68C_and_Unix
Kusalananda
1
Les blocs de droite et délimités par des mots clés ont également été utilisés dans d'autres langues de la famille Algol, y compris Pascal (qui utilise begin ... endetc.).
alexis
2
Je n'avais pas entendu l'histoire od, c'est drôle ... (Bien que, pourquoi ne pas simplement finir avec des boucles pour rof, alors?)
alexis
2
@alexis Eh bien, comme l'a dit Kusalananda, cela vient d'Algol 68, c'est le point clé. Stephen Bourne, le créateur du shell Bourne original, a été fortement influencé par ce langage, et c'est pourquoi il s'en est tenu à cette syntaxe. Même quand il écrivait en C. Voir le code source du bourne shell: minnie.tuhs.org//cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h Oh, et par le chemin, BEGINet y ENDsont également définis.
Sergiy Kolodyazhnyy
1
Tout ce style de formatage vient également d'Algol 68, soit dit en passant. Son FORet DOserait également sur des lignes distinctes, par convention, sauf lorsque la boucle entière pourrait facilement tenir sur une seule ligne.
reinierpost
3

Je suis surpris que personne n'ait encore mentionné cette syntaxe valide et portable:

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

Notez bien cela foret doêtes sur la même ligne, sans point-virgule. Résultat:

alfa
bravo
charlie
Steven Penny
la source
J'approuve cette réponse pour avoir branché une mention de cette syntaxe obscure (mais critique pour un code shell propre et portable dans certains cas), mais cela vaut la peine d'expliquer explicitement aux gens que cela encombre les paramètres positionnels, et aussi, je me sens obligé de mentionner que le seul formulaire «vraiment portable (tm)» est celui où se trouvent for qet dosur des lignes distinctes (le formulaire dans cet exemple n'était pas pris en charge il y a quelques décennies sur le shell Almquish d'origine ash): in-ulm.de/~mascheck/various/ bourne_args / # endnote )
mtraceur
Bien que l'exemple de cette réponse fonctionne pour moi, l'appliquer à l'exemple de la question OP ne fonctionne pas .
Scribblemacher
3

Plusieurs bonnes réponses ici. Prenez toujours des guides de style avec un grain de sel, et à mon humble avis et l'expérience, soyez toujours très légèrement à modérément préoccupé par toute communauté qui est en proie à un dogme excessif en matière de style. C'est presque comme s'ils pensaient que lorsqu'ils obtiendraient FINALEMENT le dernier pointillé et le dernier T croisé, le logiciel fonctionnerait. Parfois, il faut plus qu'un style parfait pour supprimer les bugs ...

Quand j'ai commencé à apprendre le shell, la plupart des scripts et des tutes utilisaient le format point-virgule en ligne

for i in "$@"; do
    stuff
done

mais parce que j'étais inexpérimenté, j'ai eu un peu de mal à repérer le; et do - tous deux essentiels pour confirmer l'exactitude syntaxique. J'ai donc préféré le faire sur la ligne suivante tout seul. Je ne fais plus ça (jeu de mots voulu)

De plus, la commande "while" est un excellent candidat pour un petit truc sympa:

while prep1; prep2; condition; do
    stuff
done

mais lorsque les commandes de préparation sont un peu volumineuses et / ou que la condition est complexe, elle est mieux formatée comme

while
    prep1
    prep2
    condition
do
    stuff
done

puis ajouter le faire comme "; faire" est positivement faux.

Vous pouvez même devenir plus intense que cela:

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

parce que chaque déclaration est une expression. Remarquez comment les deux styles sont utilisés de manière opportuniste. Gardez-le propre et il est tout à fait lisible. Compactez-le ou contorsionnez-le au nom du style ou de "gagner de l'espace" et cela devient un horrible bordel.

Alors! Étant donné le style plutôt baroque des scripts shell en général, tout ce qui vise à accroître la clarté et à faciliter l'accès visuel aux symboles significatifs est toujours une bonne chose.

La forme où "do" est écrit en ligne avec la commande est douce quand vous avez une petite commande - je ne trouve pas le "do" visuellement caché, ni la commande intérieure vraiment obscurcie:

for i in whatever
  do stuff
done

Je trouve cela assez agréable à regarder, et il a des analogues avec while, si et cas:

while condition
  do stuff
end

if condition
  then stuff1
  else stuff2
fi

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

La clarté et la propreté générale sont tout ce que Codd * vous demande.

* Edgar F. Codd, père de la théorie des bases de données relationnelles.


la source
1
Jamais vu un whileavec une ifcondition avant. Cool!
Joe