Website-Suche

Bash-Loops mit Beispielen


Sind Sie bereit, in das Bash-Looping einzutauchen? Mit der Popularität von Linux als freies Betriebssystem und der Leistungsfähigkeit der Bash-Befehlszeilenschnittstelle kann man noch weiter gehen und erweiterte Schleifen direkt von der Befehlszeile oder innerhalb von Bash-Skripten codieren.

Mit dieser Leistungsfähigkeit kann man jedes Dokument, jeden Satz von Dateien manipulieren oder fortschrittliche Algorithmen fast jeder Art und Art implementieren. Es ist unwahrscheinlich, dass Sie auf Einschränkungen stoßen, wenn Sie Bash als Grundlage für Ihr Skripting verwenden, und Bash-Schleifen sind ein leistungsstarker Teil davon.

Allerdings können Bash-Schleifen in Bezug auf die Syntax manchmal knifflig sein, und das umgebende Wissen ist von größter Bedeutung. Heute stellen wir Ihnen eine Reihe von Bash-Loop-Beispielen vor, die Ihnen helfen, sich schnell weiterzubilden und Bash-Loop-Beherrschung zu erlangen! Fangen wir an!

In diesem Tutorial lernen Sie:

  • Funktionsweise von Bash-basierten Schleifen für, während und bis, mit Beispielen
  • Wie Bash das Beenden von Schleifenstart-Anweisungen erfordert, bevor der do...done-Abschnitt der Schleife folgen kann, und wie dies mit if- und anderen Anweisungen zusammenhängt
  • So implementieren Sie grundlegende und mittelfortgeschrittene Bash-Loops
  • Funktionsweise von Subshells und Verwendung in Bereichsdeklarationen für Bash-Schleifen
  • Wie man Codierungsschleifen defensiv startet, um Fehler in der Ausgabe zu vermeiden
  • Wie man Einzeiler (ein gebräuchlicher Begriff, der unter Bash-Entwicklern verwendet wird) auf der Befehlszeile codiert, anstatt denselben Code in einem Bash-Skript zu implementieren
  • Wie die Syntaxsprache ; eine wichtige Angelegenheit ist, wenn es um die Codierung von Bash-Schleifen geht, sowohl auf der Kommandozeile als auch in Skripten

Bash Scripting – Bash Loops mit Beispielen

Beispiele für Bash-Loops

  1. Beginnen wir mit einer grundlegenden for-Schleife:

    for i in $(seq 1 5); do echo $i; done
    1
    2
    3
    4
    5

    Wie Sie sehen können, sind grundlegende for-Schleifen in Bash relativ einfach zu implementieren. Hier sind die Schritte:

    for: Gibt an, dass wir eine neue for-basierte Schleife starten möchten
    i: eine Variable, die wir verwenden werden, um den von der Klausel generierten Wert innerhalb des in-Schlüsselworts zu speichern (nämlich die Sequenz direkt darunter)
    $ (seq 1 5): Dies führt einen Befehl in einer anderen Sub-Shell aus.

    Um zu verstehen, wie dies funktioniert, betrachten Sie dieses Beispiel:

    seq 1 5
    1
    2
    3
    4
    5

    Grundsätzlich kann die $() Syntax immer (und überall!) verwendet werden, wenn Sie eine neue Subshell starten möchten. Dies ist eine der leistungsstärksten Funktionen der Bash-Shell. Betrachten Sie zum Beispiel:

    cat test.txt
    1
    2
    echo "$(cat test.txt | head -n1)"
    1

    Wie Sie sehen können, hat hier die Unterschale 'cat test.txt | head -n1' ('head -n1' wählt nur die erste Zeile aus) und gab dann die Ausgabe dieser Subshell wieder.

    Fahren wir mit der Analyse unserer obigen for-Schleife fort:

    ;: Das ist sehr wichtig. In der Bash muss jede "Aktion", wie z.B. eine startende 'for'-Schleife oder ein 'if'-Anweisungstest oder eine while-Schleife usw. mit einem ' beendet werden; ’. So kann die '; ' ist hier *vor* dem Tun, nicht danach. Betrachten Sie dies als sehr ähnlich, wenn Beispiel:

    if [ "a" == "a" ]; then echo "yes!"; fi
    yes!

    Beachten Sie, dass das ; wieder vor dem Dann und nicht danach steht. Bitte lassen Sie sich davon nicht verwirren, wenn Sie Skripte für oder while-Schleifen, if-Anweisungen usw. erstellen. Denken Sie daran, dass jede Aktion vor jeder neuen Aktion beendet werden muss, und daher für oder if vor der nächsten Aktion beendet werden muss, die im if-Anweisungsbeispiel "dann" ist, und do in der for-Schleife oben!

    Schließlich haben wir:

    do: Darauf hinweisen, dass für das, was vor ... tun... was danach kommt. Beachten Sie nochmals, dass dieses Aktionswort nach dem schließenden ; verwendet wird, um die öffnende Anweisung für die for-Schleife zu schließen.

  2. echo $i: Hier geben wir den in der Variablen i gespeicherten Wert aus ($i)
    ;: Beenden Sie die echo-Anweisung (beenden Sie jede Aktion)
    done: Geben Sie an, dass dies das Ende unserer Schleife ist

  3. Nehmen wir das gleiche Beispiel, schreiben es aber anders:

    for i in 1 2 3 4 5; do echo $i; done
    1
    2
    3
    4
    5

    Sie können jetzt sehen, wie dies mit dem obigen Beispiel zusammenhängt; Es ist derselbe Kommentar, obwohl wir hier keine Subshell verwendet haben, um eine Eingabesequenz für uns zu generieren, sondern sie manuell selbst angegeben haben.

  4. Bringt dich das ein bisschen dazu, über mögliche Einsatzmöglichkeiten zu rasen? Also sollte 🙂 es jetzt etwas Cooles damit machen.

  5. Erhöhung der Komplexität unserer for-Schleife, um Dateien einzuschließen:

    ls
    1.txt  2.txt  3.txt  4.txt  5.txt
    head -n1 *.txt
    ==> 1.txt <==
    1
    
    ==> 2.txt <==
    1
    
    ==> 3.txt <==
    1
    
    ==> 4.txt <==
    1
    
    ==> 5.txt <==
    1
    
    for i in $(ls *.txt); do cat "$i" | head -n1; done
    1
    1
    1
    1
    1

    Können Sie sich vorstellen, was hier passiert? Wenn wir uns die neuen Teile dieser for-Schleife ansehen, sehen wir:
    $ (ls *.txt): Dies listet alle txt-Dateien im aktuellen Verzeichnis auf, und beachten Sie, dass der Name dieser Dateien in der i-Variablen gespeichert wird, eine Datei pro/für jede Schleife, die die for-Schleife durchlaufen wird.

    Mit anderen Worten, wenn die Schleife (der Teil zwischen do und done) zum ersten Mal stattfindet, enthält $i 1.txt. Der nächste Lauf $i enthält 2.txt usw.

  6. cat "$i" | head -n1: Hier nehmen wir die $i Variable (wie wir gesehen haben, wird diese 1.txt, gefolgt von 2.txt usw.) und cat diese Datei (zeigt sie an) und nehmen die erste Zeile desselben Kopfes -n1. Somit wird 5 mal 1 ausgegeben, da dies die erste Zeile in allen 5 Dateien ist, wie wir am vorherigen Kopf -n1 in allen .txt Dateien sehen können.

  7. Wie wäre es jetzt mit einem sehr komplexen?

    tail -n1 *.txt
    ==> 1.txt <==
    1
    
    ==> 2.txt <==
    2
    
    ==> 3.txt <==
    3
    
    ==> 4.txt <==
    4
    
    ==> 5.txt <==
    5
    
    for i in $(ls *.txt 2>/dev/null); do echo -n "$(tail -n1 $i)"; echo " from $i !" ; done
    1 from 1.txt !
    2 from 2.txt !
    3 from 3.txt !
    4 from 4.txt !
    5 from 5.txt !
    

    Kannst du trainieren, was hier passiert?

    Lassen Sie es uns Schritt für Schritt analysieren.

    denn ich in : Das wissen wir bereits; Starten Sie eine neue for-Schleife, weisen Sie die Variable I dem zu, was in der In-Klausel folgt
    $ (ls *.txt 2>/dev/null): Das Gleiche wie der obige Befehl; Listen Sie alle TXT-Dateien auf, aber diesmal mit einem definitiven Fehlervermeidungsschutz. Schauen:

    for i in $(ls i.do.not.exist); do echo "just testing non-existence of files"; done
    ls: cannot access 'i.do.not.exist': No such file or directory
    

    Nicht sehr professionelle Ausgabe! So;

    for i in $(ls i.do.not.exist 2>/dev/null); do echo "just testing non-existence of files"; done
    

    Diese Anweisung generiert keine Ausgabe.

    Setzen wir unsere Analyse fort:

    ; do: Beenden Sie die Startanweisung für die Schleife, beginnen Sie die DO... done Abschnitt unserer Schleifendefinition
    echo -n "$ (tail -n1 $i)";: Zunächst steht das -n für do not output the trailing newline am Ende der angeforderten Ausgabe.

    Als nächstes nehmen wir die letzte Zeile jeder Datei. Beachten Sie, wie wir unseren Code von oben optimiert haben? d.h. anstatt cat file.txt | tail -n1 zu machen, kann man einfach tail -n1 file.txt machen - eine Abkürzung, die neue Bash-Entwickler leicht übersehen können. Mit anderen Worten, hier drucken wir einfach 1 (die letzte Zeile in 1.txt), unmittelbar gefolgt von 2 für 2.txt usw.

    Als Randnotiz, wenn wir den nachfolgenden Befehl echo nicht angegeben hätten, wäre die Ausgabe einfach 12345 ohne Zeilenumbrüche gewesen:

    for i in $(ls *.txt 2>/dev/null); do echo -n "$(tail -n1 $i)"; done
    12345$

    Beachten Sie, dass nicht einmal der letzte Zeilenumbruch vorhanden ist, daher die Ausgabe vor der Eingabeaufforderung $ zurückkehrt.

    Schließlich haben wir echo " von $i !"; (zeigt uns die Ausgabe von 1.txt !) und das Schließen der Schleife durch das done.

    Ich hoffe, Sie können inzwischen sehen, wie mächtig das ist und wie viel Kontrolle man über Dateien, Dokumentinhalte und mehr ausüben kann!

    Lassen Sie uns als nächstes eine lange zufällige Zeichenkette mit einer while-Schleife generieren! Spaß?

  8. Verwenden einer while-Schleife zum Generieren einer zufälligen Zeichenfolge:

    RANDOM="$(date +%s%N | cut -b14-19)"
    COUNT=0; MYRANDOM=; while true; do COUNT=$[ ${COUNT} + 1 ]; if [ ${COUNT} -gt 10 ]; then break; fi; MYRANDOM="$MYRANDOM$(echo "${RANDOM}" | sed 's|^\(.\).*|\1|')"; done; echo "${MYRANDOM}"
    6421761311

    Das sieht komplex aus! Lassen Sie es uns Schritt für Schritt analysieren. Aber sehen wir uns zuerst an, wie dies in einem Bash-Skript aussehen würde.

  9. Beispiel für die gleiche Funktionalität, implementiert in einem Bash-Skript:

    cat test.sh
    #!/bin/bash
    
    RANDOM="$(date +%s%N | cut -b14-19)"
    
    COUNT=0
    MYRANDOM=
    
    while true; do 
      COUNT=$[ ${COUNT} + 1 ]
      if [ ${COUNT} -gt 10 ]; then 
        break
      fi
      MYRANDOM="$MYRANDOM$(echo "${RANDOM}" | sed 's|^\(.\).*|\1|')"
    done
    
    echo "${MYRANDOM}"
    chmod +x test.sh
    ./test.sh
    1111211213
    ./test.sh 
    1212213213
    

    Es ist manchmal ziemlich überraschend, dass solch komplexer Bash-Looping-Code so einfach in einen "One-Liner" verschoben werden kann (ein Begriff, den Bash-Entwickler verwenden, um sich auf das zu beziehen, was in Wirklichkeit ein kleines Skript ist, das jedoch direkt von der Befehlszeile aus implementiert wird, normalerweise in einer einzigen (oder maximal wenigen) Zeile.

    Beginnen wir nun mit der Analyse unserer letzten beiden Beispiele – die sich sehr ähnlich sind. Die kleinen Unterschiede im Code, insbesondere im Bereich der Redewendung '; ' werden in Beispiel 7 unten erläutert:

    RANDOM="$ (date +%s%N | cut -b14-19)" on Zeile 4: Dies nimmt (mit cut -b14-19) die letzten 6 Ziffern der aktuellen Epochenzeit (die Anzahl der Sekunden, die seit dem 1. Januar 1970 vergangen sind), wie sie durch das Datum +%s%N gemeldet wird, und weist die generierte Zeichenkette der Variablen RANDOM zu, wodurch eine halbzufällige Entropie auf den RANDOM-Pool gesetzt wird, Vereinfacht ausgedrückt "den Zufallspool etwas zufälliger machen".

    COUNT=0 auf Zeile 6: Setzen Sie die Variable COUNT auf 0

    MYRANDOM= on Zeile 7: Setze die MYRANDOM-Variable auf 'leer' (kein Wert zugewiesen)

    während... tun... erledigt zwischen Zeile 9 und Zeile 15: das sollte jetzt klar sein; Starten Sie eine while-Schleife, führen Sie den Code zwischen den do... done-Klauseln.

    true: und solange die Anweisung, die auf das 'while' folgt, als true ausgewertet wird, wird die Schleife fortgesetzt. Hier ist die Anweisung 'true', was bedeutet, dass es sich um eine unbestimmte Schleife handelt, bis eine break-Anweisung angegeben wird.

    COUNT=$[ $ {COUNT} + 1 ] on Zeile 10: Erhöhen Sie unsere COUNT-Variable um 1

    if [ $ {COUNT} -gt 10 ]; then on Zeile 11: Eine if-Anweisung, um zu überprüfen, ob unsere Variable größer als -gt 10 ist, und wenn ja, führen Sie die then... FI-Teil

    break on Zeile 12: Dies unterbricht die unbestimmte while-Schleife (d.h. wenn COUNT größer als 10 ist, endet die Schleife)

    MYRANDOM="... on Zeile 14: Wir werden MYRANDOM einen neuen Wert zuweisen

    $MYRANDOM auf Zeile 14: Nehmen wir zuerst, was wir bereits in dieser Variablen haben, mit anderen Worten, wir werden etwas am Ende dessen anhängen, was bereits vorhanden ist, und dies für jede weitere Schleife

    $ (echo "$ {RANDOM}" | sed 's|^\(.\).*|\1|') on Zeile 14: Dies ist der Teil, der jedes Mal hinzugefügt wird. Im Grunde genommen gibt es die Variable RANDOM zurück und nimmt das erste Zeichen dieser Ausgabe mit einem komplexen regulären Ausdruck in sed an. Sie können diesen Teil ignorieren, wenn Sie möchten, im Grunde heißt es "nehmen Sie das erste Zeichen der Ausgabe der Variablen $RANDOM und verwerfen Sie alles andere"

    So können Sie sehen, wie die Ausgabe (z.B. 1111211213) erzeugt wird; jeweils ein Zeichen (von links nach rechts) mit der while-Schleife, die als Ergebnis der Überprüfung der Zählervariablen COUNT 10 Mal in einer Schleife ausgeführt wird.

    Warum also wird die Ausgabe oft im Format 1,2,3 und weniger von anderen Zahlen ausgegeben? Dies liegt daran, dass die Variable RANDOM eine halbzufällige Variable (basierend auf dem Startwert RANDOM=...) zurückgibt, die im Bereich von 0 bis 32767 liegt. Daher beginnt diese Zahl oft mit 1, 2 oder 3. Zum Beispiel wird 10000-19999 alle in 1 usw. zurückgegeben, da das erste Zeichen der Ausgabe immer von der sed übernommen wird!

  10. Ein kurzes Skript, um die Möglichkeit hervorzuheben, Bash-Looping-Code auf eine andere Weise anzuordnen (oder zu gestalten), ohne das ;-Idiom zu verwenden.

    Wir müssen die kleinen Unterschiede zwischen dem Bash-Skript und dem einzeiligen Befehlszeilenskript klären.

    NOTE
    Beachten Sie, dass es im Bash-Skript (test.sh) nicht so viele ;-Redewendungen gibt. Dies liegt daran, dass wir den Code jetzt auf mehrere Zeilen aufgeteilt haben und ein ; nicht erforderlich ist, wenn stattdessen ein EOL-Zeichen (End of Line) vorhanden ist. Ein solches Zeichen (Zeilenumbruch oder Wagenrücklauf) ist in den meisten Texteditoren nicht sichtbar, aber es ist selbsterklärend, wenn man bedenkt, dass jeder Befehl in einer separaten Zeile steht.

    Beachten Sie auch, dass Sie die do-Klausel der while-Schleife auch in der nächsten Zeile platzieren können, so dass es unnötig wird, das ; dort überhaupt zu verwenden.

    cat test2.sh 
    #!/bin/bash
    
    for i in $(seq 1 3)
    do 
      echo "...looping...$i..." 
    done
    ./test2.sh 
    ...looping...1...
    ...looping...2...
    ...looping...3...
    

    Ich persönlich bevorzuge den in Beispiel 6 angegebenen Syntaxstil, da es klarer zu sein scheint, was die Absicht des Codes ist, indem die Schleifenanweisung vollständig in einer Zeile geschrieben wird (wie bei anderen Programmiersprachen), obwohl die Meinungen und Syntaxstile je nach Entwickler oder Entwicklergemeinschaft unterschiedlich sind.

  11. Werfen wir zum Schluss einen Blick auf eine Bash-bis-Schleife:

    NR=0; until [ ${NR} -eq 5 ]; do echo "${NR}"; NR=$[ ${NR} + 1 ]; done
    0
    1
    2
    3
    4

    Analysieren wir dieses Beispiel:

    NR=0: Setze hier eine Variable namens NR auf null
    bis: Wir starten unsere 'bis' Schleife
    [ $ {NR} -eq 5 ]: Dies ist unsere if-Bedingung, oder besser unsere bis-Bedingung. Ich sage if as Die Syntax (und die Arbeitsweise) ist ähnlich wie die des Testbefehls, d.h. des zugrunde liegenden Befehls, der in if-Anweisungen verwendet wird. In Bash kann der Testbefehl auch durch einzelne Klammern [' '] dargestellt werden. Die Testmittelwerte $ {NR} -Gl 5; Wenn unsere Variable NR 5 erreicht, wird der Test wahr, wodurch wiederum die Unify-Schleife endet, wenn die Bedingung erfüllt wird (eine andere Möglichkeit, dies zu lesen, ist als "bis wahr" oder "bis unsere NR-Variable 5 ist"). Beachten Sie, dass, sobald NR 5 ist, der Schleifencode nicht mehr ausgeführt wird, daher ist 4 die letzte angezeigte Zahl.
    ;: Beenden Sie unsere until-Anweisung, wie oben erklärt
    do: Starten Sie unsere Aktionskette, die ausgeführt werden soll, bis die getestete Anweisung wahr/gültig wird
    echo "$NR; ": Echo des aktuellen Wertes unserer Variablen NR
    NR=$[ $ {NR} + 1 ];: Erhöht unsere Variable um eins. Die $[' ... Die Berechnungsmethode '] ist spezifisch für Bash
    done: Beenden Sie unseren Aktionsketten-/Schleifencode

    Wie Sie sehen können, sind die While- und Until-Schleifen von Natur aus sehr ähnlich, obwohl sie in Wirklichkeit Gegensätze sind. While-Schleifen werden so lange ausgeführt, wie etwas wahr/gültig ist, während Unified-Schleifen so lange ausgeführt werden, wie etwas "noch nicht gültig/wahr" ist. Oft sind sie austauschbar, indem der Zustand umgekehrt wird.

  12. Schlussfolgerung

    Ich vertraue darauf, dass Sie anfangen können, die Macht von Bash zu erkennen, und insbesondere von for, while und until Bash. Wir haben hier nur an der Oberfläche gekratzt, und ich werde vielleicht später mit weiteren fortgeschrittenen Beispielen zurückkommen. Hinterlassen Sie uns in der Zwischenzeit einen Kommentar darüber, wie Sie Bash-Schleifen in Ihren täglichen Aufgaben oder Skripten verwenden. Genießen!

Verwandte Artikel: