Tracks
/
Bash
Bash
/
Lehrplan
/
Schleifen
Sc

Schleifen in Bash

{one: "1 Übung", other: "%{count} Übungen"}

Über Schleifen

Bash kennt zwei Arten von Schleifen:

  • Einige Befehle für jedes Element einer Liste von Elementen wiederholen,
  • Einige Befehle wiederholen, solange eine Bedingung wahr (oder falsch) ist.

for-Schleifen

Um über eine Liste von Elementen zu iterieren, verwenden wir die for-Schleife.

for varname in words; do COMMANDS; done

words wird durch Worttrennung und Dateinamenexpansion expandiert (was wir im Quoting-Konzept kennengelernt haben). Jedes Wort wird der Reihe nach der Variable varname zugewiesen und die COMMANDS werden ausgeführt.

Hier sind einige Beispiele, die zeigen, wann die for-Schleife nützlich sein kann:

  • Einige Befehle für eine Gruppe von Dateien ausführen.

    # source all the bash library files in the current directory
    for file in ./*.bash; do
        source "$file"
    done
    
  • Einen Befehl für jeden Parameter eines Skripts oder einer Funktion ausführen.

    for arg in "$@"; do
        echo "argument: ${arg}"
    done
    
  • Einen Befehl für jedes durch Whitespace getrennte Wort in der Ausgabe eines Befehls ausführen.

    for i in $(seq 10); do
        echo "${i} squared is $((i * i))"
    done
    

    Zu diesem Stil kommen später noch einige Warnungen.

Arithmetische for-Schleife

Bash hat tatsächlich eine arithmetische Schleife. Das dürfte dir aus anderen Programmiersprachen bekannt vorkommen.

for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done

Die doppelten runden Klammern in Bash stehen für einen arithmetischen Kontext (mehr zur Arithmetik in Bash sehen wir in einem späteren Konzept). Das obige Beispiel mit seq lässt sich so schreiben:

for ((i = 1; i <= 10; i++)); do
    echo "${i} squared is $((i * i))"
done

Wann du keine for-Schleife verwenden solltest

Lies keine Zeilen mit for.

Ein Anti-Pattern, das dir oft begegnet: über die Ausgabe von cat zu iterieren.

for line in $(cat some.file); do 
    do_something_with "$line"
done

Das ist aus zwei Gründen falsch.

  1. Die Befehlssubstitution steht nicht in Anführungszeichen und unterliegt daher der Worttrennung. Die Worttrennung trennt standardmäßig an Whitespace, nicht nur an Zeilenumbrüchen. Diese for-Schleife iteriert über die Wörter in der Datei, nicht über die Zeilen.
  2. Die Befehlssubstitution steht nicht in Anführungszeichen und unterliegt daher der Dateinamenexpansion. Jedes Wort in der Datei wird als Glob-Muster interpretiert.

Wie wir im Quoting-Konzept gelernt haben, lässt sich die Worttrennung mit der Variable IFS steuern und die Dateinamenexpansion abschalten. Doch meist ist das eine fragile Lösung. for ist die falsche Methode, um über die Zeilen einer Datei zu iterieren. Eine Datei liest man idiomatischerweise mit einer while-Schleife.

while-Schleifen

Verwende while, um eine Folge von Befehlen zu wiederholen, solange eine Bedingung wahr ist.

while CONDITION_COMMANDS; do COMMANDS; done

Wie bei if (wie wir im Conditionals-Konzept gelernt haben, gibt es keine besondere Syntax für CONDITION_COMMANDS. Der Exit-Status der Befehlsliste entscheidet über „wahr“ oder „falsch“.

Schleifen steuern

Der Befehl break springt aus der Schleife heraus. Die Ausführung geht mit dem Befehl weiter, der auf das abschließende done der Schleife folgt.

Der Befehl continue springt zur nächsten Iteration der Schleife.

Die Zeilen einer Datei lesen

Wie erwähnt ist eine while-Schleife die idiomatische Art, eine Datei zu lesen.

while IFS= read -r line; do
    do_something_with "$line"
done < some.file
  • Der Inhalt der Datei wird der Schleife über die Umleitung < als Eingabe bereitgestellt.

  • Der Befehl read gibt „wahr“ zurück, wenn er eine vollständige Zeile aus seiner Eingabe lesen kann. Wenn die Eingabe aufgebraucht ist oder die letzte Zeile ohne abschließenden Zeilenumbruch endet, gibt read „falsch“ zurück.

    • Die wirklich idiomatische Art, die Zeilen einer Datei zu lesen, selbst wenn die letzte Zeile nicht mit einem Zeilenumbruch endet, ist

      while IFS= read -r line || [[ -n "$line" ]]; do ...
      
  • Die Option -r weist read an, Backslash-Sequenzen nicht zu ersetzen: Ein Backslash ist einfach ein normales Zeichen.

  • IFS= weist IFS nur für die Dauer des read-Befehls die leere Zeichenkette zu. Dadurch wird die Worttrennung vorübergehend abgeschaltet, sodass führender oder abschließender Whitespace in der eingehenden Textzeile erhalten bleibt.

Until

Das Konstrukt until wiederholt eine Folge von Befehlen, solange eine Bedingung falsch ist. Die Schleife wiederholt sich, bis die Bedingung wahr wird.

until CONDITION_COMMANDS; do COMMANDS; done

until wird selten verwendet. Öfter verwendet man eine „while not“-Schleife.

while ! CONDITION_COMANDS; do ...

Endlosschleifen

Manchmal möchtest du eine Schleife endlos laufen lassen. Hier sind zwei Möglichkeiten dafür.

  1. eine while-Schleife mit einer Bedingung, die immer einen Erfolgs-Exit-Status hat

    while true; do ...
    
  2. eine arithmetische for-Schleife mit leeren Ausdrücken

    for ((;;)); do ...
    

Do-While

Es gibt kein explizites do-while-Konstrukt, aber du kannst denselben Effekt erreichen:

while true; do
    COMMANDS

    if END_CONDITION; then
        break
    fi
done
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab