Warum muss ich "do" in die gleiche Zeile wie "for" setzen?

28

1. Zusammenfassung

Ich verstehe nicht, warum ich die E010-Bashate-Regel brauche .


2. Einzelheiten

Ich benutze bashate zum Flusen von .shDateien. E010-Regel:

tun nicht auf der gleichen Linie wie für

for bashate:

  • Richtig:

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

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

Gibt es irgendwelche gültigen Argumente, warum ich forund doin der gleichen Zeile brauche ?


3. Nicht nützlich

Ich kann keine Antwort auf meine Frage finden in:

  1. Google
  2. Artikel über bewährte Codierungsmethoden ( Beispiel )
  3. bashate Dokumentation . Ich finde nur :

    Eine Reihe von Regeln, mit denen die Konsistenz in Kontrollblöcken aufrechterhalten werden kann. Diese werden in langen Zeilen ignoriert, die eine Fortsetzung haben, weil das Abrollen irgendwie "interessant" ist.

Саша Черных
quelle
3
Die Einrückung doist auf jeden Fall ein bisschen ungewöhnlich, aber for ... \ndo\n<indent>body...sehr häufig und ich würde sogar mehr schätzen als for ... ; do. Beschwert es sich auch darüber?
Michael Homer
20
bashateist ein Stil - Checker. Stile sind von Natur aus subjektiv. Verwenden Sie es nicht, wenn Sie den Artibrary-Stil nicht mögen, den es auferlegt. Sie sollten stattdessen einen Syntax- / Bug-Checker wie Shellcheck in Betracht ziehen .
Meuh
@meuh, danke, ich benutze bereits ShellCheck. meine Frage: E010- nur Stil - Regel oder in einigen Fällen brauche ich für und tue nur in der gleichen Zeile nicht durch Stil Gründe.
Саша Черных
10
Es gibt keine syntaktische Verpflichtung, in der Shell für dieselbe Zeile zu arbeiten und dies zu tun .
Meuh
1
@ Саша Черных Es ist nicht die Einrückung an sich, die ungewöhnlich ist, es ist die Einrückung von do. Es ist wie das Einrücken der öffnenden Klammer eines ifund das Hinzufügen von Code in derselben Zeile in einer Sprache wie C. Ein anderes Beispiel, wenn Python dies zulässt, wäre das Einrücken :eines ifEinrückungszeichens in die nächste Zeile und das Hinzufügen von Code in derselben Zeile. Es wird sich durch zusätzliche Linien im Körper unterscheiden.
JoL

Antworten:

60

Syntaktisch sind die folgenden zwei Codeausschnitte korrekt und äquivalent:

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

Letzteres ist möglicherweise schwerer zu lesen, da es doden Befehl im Hauptteil der Schleife leicht verschleiert. Wenn die Schleife mehrere Befehle enthält und sich der nächste Befehl in einer neuen Zeile befindet, wird die Verschleierung weiter hervorgehoben:

for f in *
    do cmd1
    cmd2
done

... aber es als "Fehler" zu kennzeichnen, ist meiner Meinung nach eher die persönliche Meinung eines Menschen als eine objektive Wahrheit.

Im Allgemeinen kann fast jede ;Zeile durch eine neue Zeile ersetzt werden. Sowohl ;als auch newline sind Befehlsabschlusszeichen. doist ein Schlüsselwort, das bedeutet "hier folgt, was zu tun ist (in dieser forSchleife)".

for f in *; do ...; done

ist das gleiche wie

for f in *
do
   ...
done

und wie

for f in *; do
   ...
done

Der Grund für die Überlagerung ist die Lesbarkeit und die lokalen / persönlichen Stilkonventionen.


Persönliche Meinung:

Ich halte es für sinnvoll , in sehr langen Loop - Headern doeine neue Zeile einzufügen , wie in

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

oder

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

Gleiches gilt für die thenin einer ifAussage.

Aber auch hier kommt es auf die persönlichen Stilvorlieben an oder auf den Kodierungsstil, den das Team / Projekt verwendet.

Kusalananda
quelle
Sie sagen: "In Schleifen-Headern, die sehr lang sind, ist es möglicherweise sinnvoll, do in eine neue Zeile einzufügen." Könnten Sie einen Grund dafür nennen? In Anbetracht , dass der Header muß durch folgen do, ich sehe keinen Grund , warum es in der nächsten Zeile setzen würde Lesbarkeit helfen.
Konrad Rudolph
3
@KonradRudolph Mein Terminal ist 80 Zeichen breit. Wenn die Liste umgebrochen wird, mache ich es zu einer Reihe von fortgesetzten Zeilen (wie in meinem letzten Beispiel). Wenn es fast umgebrochen wird, setze ich das do(oder then) in eine eigene Zeile (wie im vorletzten Beispiel). Dies alles hat mit persönlichen Vorlieben zu tun. Ich mag keine zu langen Zeilen, teilweise, weil mein Terminal "nur" 80 Zeichen breit ist, und teilweise, weil ich finde, dass es unordentlich aussieht. Ich finde es auch schwierig, sehr lange Zeilen nach Fehlern zu durchsuchen.
Kusalananda
1
Es erscheint unnötig, weiter darauf hinzuweisen, dass dies eine Meinung ist. bashate ist ein Styleguide und basiert von Natur aus auf Meinungen.
Barmar
4
@Barmar, beachte, dass die Frage hier Formulierungen wie "Need to" und "Rule" verwendet und die Bashate-Readme-Datei do"Error" in einer separaten Zeile anzeigt . Das sind ziemlich strenge Formulierungen, daher scheint es sich zu lohnen, darauf hinzuweisen, dass die sogenannte "Regel" im Gegenteil nur eine subjektive Meinung ist.
ilkkachu
2
@mtraceur Richtig, ich stelle persönliche Vorlieben nicht in Frage. Beachten Sie jedoch, dass das von Ihnen angegebene Lesbarkeitsspaltenlimit nicht für Code gilt. Es gilt nur für die Prosa. Die Augenbewegung beim Codelesen unterscheidet sich grundlegend, sodass die Beweise aus diesen Studien hier nicht zutreffen. Und aus historischen Gründen, die nicht mehr als Begründung gelten, haben wir auch frühere Dateinamen als 8.3 verwendet.
Konrad Rudolph
28

Beachten Sie, was oben auf der Seite steht:

bashate: Ein pep8-Äquivalent für Bash-Skripte

PEP8 ist der Style Guide für Python-Code. Während Python-Leute ihre Stilprobleme oft sehr ernst zu nehmen scheinen [Zitat erforderlich] , ist es nur das, ein Leitfaden. Wir könnten uns Upsides einfallen lassen, um beide doin die gleiche Zeile wie die zu setzenfor zu setzen und um sie in eine eigene Zeile zu setzen.

Es ist die gleiche Diskussion wie {beim Starten eines ifoder eines whileBlocks (oder eines solchen), wo der Code in C abgelegt werden soll .


Ein paar Zeilen weiter unten in der Dokumentation gibt es eine andere interessante Regel:

E020: Funktionsdeklaration nicht im Format ^function name {$

Ich gehe davon aus, dass der Autor dieses Styleguides der Meinung ist, dass die Verwendung des functionSchlüsselworts erforderlich ist, damit der Leser eine Funktionsdeklaration erkennt. Dies function fooist jedoch keine Standardmethode zum Definieren einer Funktion: Die Standardmethode istfoo() . Der einzige Unterschied zwischen den beiden (in Bash) ist, dass es schwieriger ist, die andere auf eine Standard-Shell zu portieren/bin/sh in Debian oder Ubuntu.

Daher würde ich vorschlagen, alle diese Styleguides mit ein oder drei Körnern zu nehmen und selbst zu entscheiden, welcher Style der beste ist. Mit einem guten Style-Checker können Sie einige Checks deaktivieren (bashate muss bashate -i E010,E011diese beiden Checks ignorieren). Mit einem ausgezeichneten Style-Checker können Sie die Tests modifizieren, z. B. um hier nach dem Gegenteil von E020 zu suchen.

ilkkachu
quelle
12

TL; DR: Das musst du nicht. Es ist nur die Meinung eines Typen.

Wie viele andere schreibe ich seit forJahrzehnten Loops wie diese:

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

Dieses Layout unterstreicht die Tatsache, dass do ... done der Schleifenkörper wie geschweifte Klammern in C-ähnlichen Sprachen umgeben ist, und ermöglicht es Zeilenumbrüchen, die Komponenten des Schleifenkonstrukts zu trennen.

Natürlich gibt es auch religiöse Kriege darüber, wo die geschweiften Klammern platziert werden sollen. Man könnte also sagen, dass die Jury über diese noch nicht entschieden hat. IMHO, dies ist eindeutig, wie dies entworfen wurde, um zu funktionieren; Borowski mochte übereinstimmende Trennzeichen, vgl. if ... fi, case ... esacUnd die Notwendigkeit für ein Semikolon in der kürzeren Version zeigt , dass Sie machen es kürzer ist als ursprünglich entworfen. Daran ist nichts auszusetzen. technologische fortschritte und viele dinge, die früher eine gute idee schienen, werden jetzt missbilligt goto. Aber bis die gesamte Shell-Scripting-Community die Präferenzen der bashateAutoren übernimmt , müssen Sie nichts tun.

alexis
quelle
3
Das fi, was entspricht if, und esacso weiter, stammt von Algol 68. Der einzige Grund, warum eine forSchleife donicht beendet odwird, odist der Name eines vorhandenen Standarddienstprogramms. Siehe en.wikipedia.org/wiki/ALGOL_68C#Algol_68C_and_Unix
Kusalananda
1
Rechte und durch Schlüsselwörter getrennte Blöcke wurden auch in anderen Sprachen der Algol-Familie verwendet, einschließlich Pascal (der begin ... endusw. verwendet).
Alexis
2
Hatte die Geschichte noch nicht gehört od, das ist lustig ... (Warum also nicht einfach mit for-loops rof
aufhören
2
@alexis Nun, wie Kusalananda sagte, kommt es von Algol 68, das ist der entscheidende Punkt. Stephen Bourne, der Schöpfer der ursprünglichen Bourne-Shell, war stark von dieser Sprache beeinflusst, und deshalb hielt er an dieser Syntax fest. Sogar als er in C schrieb. Siehe den Quellcode für die Bourne-Shell: minnie.tuhs.org//cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h Oh, und von den Weg, BEGINund ENDsind dort auch definiert.
Sergiy Kolodyazhnyy
1
Dieser gesamte Formatierungsstil stammt übrigens auch aus Algol 68. Sein FORund DOwürde auch in getrennten Zeilen sein, außer wenn die gesamte Schleife leicht in eine einzelne Zeile passen würde.
reinierpost
3

Ich bin überrascht, dass noch niemand diese gültige und portable Syntax erwähnt hat:

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

Beachten Sie dies sorgfältig forund dostehen in derselben Zeile ohne Semikolon. Ergebnis:

alfa
bravo
charlie
Steven Penny
quelle
Ich bin mit dieser Antwort einverstanden, weil sie eine Erwähnung dieser obskuren (aber in einigen Fällen für sauberen und tragbaren Shell-Code kritischen) Syntax enthält. Es lohnt sich jedoch, den Leuten ausdrücklich zu erklären, dass dies die Positionsparameter überfordert, und ich fühle mich auch gezwungen, dies zu erwähnen Die einzige "wirklich tragbare" Form ist die, bei der for qund doin separaten Zeilen (das Formular in diesem Beispiel wurde vor einigen Jahrzehnten auf der ursprünglichen Almquish-Shell ( ash) nicht unterstützt ): in-ulm.de/~mascheck/various/ bourne_args / # endnote )
mtraceur
Während das Beispiel in dieser Antwort für mich funktioniert, funktioniert es nicht , es auf das Beispiel in der Frage von OP anzuwenden .
Scribblemacher
3

Hier einige gute Antworten. Nehmen Sie Styleguides immer mit einem Körnchen Salz und seien Sie meiner Meinung nach ein bisschen bis mäßig besorgt über jede Community, die in puncto Stil von übermäßigem Dogma geprägt ist. Es ist fast so, als ob sie glauben, dass die Software funktionieren wird, wenn sie das letzte Mal, dass ich gepunktet habe, und das letzte Mal, dass ich es überschritten habe, ENDLICH bekommen. Manchmal braucht es mehr als perfekten Stil, um Fehler zu entfernen ...

Als ich anfing, Shell zu lernen, verwendeten die meisten Skripte und Tutes das Inline-Semikolon-Format

for i in "$@"; do
    stuff
done

aber weil ich unerfahren war, fiel es mir ein bisschen schwer, die zu entdecken; und do - beides ist wichtig, um die syntaktische Korrektheit zu bestätigen. Also habe ich es vorgezogen, in der nächsten Zeile alles alleine zu machen. Ich mache das nicht mehr (Wortspiel beabsichtigt)

Außerdem ist der Befehl 'while' ein hervorragender Kandidat für einen kleinen Trick:

while prep1; prep2; condition; do
    stuff
done

Wenn die Vorbereitungsbefehle jedoch etwas umfangreich sind und / oder die Bedingung komplex ist, ist es besser, sie so zu formatieren

while
    prep1
    prep2
    condition
do
    stuff
done

und dann das Anhängen des do als "; do" ist positiv flüchtig.

Sie können sogar noch intensiver werden:

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

weil jede aussage ein ausdruck ist. Beachten Sie, wie beide Stile opportunistisch verwendet werden. Halten Sie es sauber und es ist gut lesbar. Kompakt oder verdreht es im Namen des Stils oder "platzsparend" und es wird ein schreckliches Durcheinander.

So! Angesichts des eher barocken Stils von Shell-Skripten im Allgemeinen ist es immer eine gute Sache, die Übersichtlichkeit und den visuellen Zugang zu wichtigen Symbolen zu verbessern.

Die Form, in der 'do' in den Befehl geschrieben ist, ist süß, wenn Sie einen kleinen Befehl haben - ich finde das 'do' weder visuell verborgen, noch ist der innere Befehl wirklich verdeckt:

for i in whatever
  do stuff
done

Ich finde das sehr angenehm anzusehen, und es hat Analogien mit while, if und case:

while condition
  do stuff
end

if condition
  then stuff1
  else stuff2
fi

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

Klarheit und allgemeine Ordnung sind alles, was Codd * von Ihnen verlangt.

* Edgar F. Codd, Vater der relationalen Datenbanktheorie.


quelle
1
Ich habe noch nie einen whilemit einer ifKrankheit gesehen. Cool!
Joe