Linux & Co.

Linux-Terminal-Basics 12: Schleifen mit for, while, until

Mit Schleifen kommt etwas Schwung in den Terminal-Alltag - und viel mehr Effizienz

Schleifen sind ein grundlegender Bestandteil jedweder Programmierung, aber auch allein für sich schon ziemlich nützlich. Kurz gesagt: Ihr könnt Befehle beliebig viele Male ausführen lassen, beispielsweise, um viele Dateien als Stapel zu verarbeiten. Oder Daten von vielen Programmen verarbeiten lassen. Oder Programme erst ausführen, wenn Bedingungen erfüllt sind Hmm, so ganz kurz geht das wohl doch nicht. .

In unserer Serie zu Linux-Terminal-Basics zeigen wir Euch, wie Ihr einige der wichtigsten Aufgaben auf der Kommandozeile erledigen könnt - vom Navigieren, über Dateioperationen, bis hin zu komplexen Suchaufträgen. Als Terminal verwenden wir Bash und auch wenn Linux im Vordergrund steht, funktioniert fast alles auch unter Windows. Und nun noch die Links zur Einleitung und zur Übersicht aller Artikel.

while und until

Deutlich bekannter ist die while-Schleife: Hier wird eine Aufgabe wiederholt ausgeführt, so lange die Bedingung erfüllt wird. Bei der until-Schleife wird die Aufgabe ausgeführt, bis die Bedingung erfüllt wird.

Zunächst zu while: Das Grundkonstrukt sieht so aus:

while Bedingung
  do Kommandos
done    

oder

while Bedingung; do Kommandos; done

Die Bedingung könnte so etwas sein wie "so lange a kleiner als 4". Aber die einfachste Form liefert wohl das Programm true: Dieses tut nichts - und das erfolgreich (steht so im Handbuch). Der Befehl true macht tatsächlich nichts, außer dem Terminal zurückzumelden, dass er erfolgreich war. Damit kann man sich eine Endlosschleife basteln:

while true
  do echo Hallo!
  sleep 1
done

Diese Schleife würde also prüfen, ob true erfolgreich ist und da es das immer ist, für die Ewigkeit im Sekundentakt "Hallo!" ausgeben.

Mit einer echten Bedingung könnte eine Schleife zum Beispiel so aussehen:

while (ping -c1 tutonaut.de)
  do sleep 10
done
echo "Warnung - tutonaut.de offline"

Hier würde also mit ping geprüft, ob die URL tutonaut.de erreichbar ist. Falls ja, pausiert sleep das Skript 10 Sekunden und es beginnt von vorn. Sobald die Bedingung nicht mehr erfüllt wird, wird die Schleife beendet und eine Warnmeldung ausgegeben.

Und nun zu until: Erinnert Euch an die Endlosschleife von oben - hier aber mit until:

until true
  do echo Hallo!
  sleep 1
done

In diesem Fall würde was passieren? Gar nichts. Denn until läuft eben so lange bis die Bedingung erfüllt wird - und das ist hier eben sofort der Fall. Die Kommandos werden also gar nicht verarbeitet.

Analog zum ping-Beispiel von oben:

until (ping -c1 tutonaut.de)
  echo "Die Seite ist online!"
done

Die Schleife läuft so lange, bis ping erfolgreich ist und meldet dann final den Erfolg. So könntet Ihr auch im eigenen Netzwerk im Auge behalten, ob zum Beispiel ein Medienserver startet.

So, und jetzt noch eine Portion Verwirrung:

while true; do echo foobar; done
until ! true; do echo foobar; done

Die beiden Schleifen machen exakt das Gleiche - endlos foobar ausgeben. Der Grund ist das ! vor true, das schlicht für "nicht" steht. Und da "nicht wahr" niemals wahr wird ... Endlosschleife halt.

Und als letzter Hinweis: Es gehen auch mehrere Bedingungen:

while ( true ; ping tutonaut.de ); do echo foobar; done

Mehrere Bedingungen setzt Ihr also per Semikolon getrennt in Klammern. Gibt es noch Luft für die for-Schleife?

for-Schleife

Im Allgemeinen werden while und until eingesetzt, wenn man keine Ahnung hat, wie oft die Schleife letztlich durchlaufen wird. Die for-Schleife geht eher von einer überschaubaren Menge an Durchläufen aus. Es wird eine Menge vorgegeben und die Kommandos laufen für jedes Element dieser Menge ein mal durch.

Das Grundskelett:

for Items (i) in Menge
  do Kommandos
done

Wirklich schön: Die Menge kann einfach aus angegebenen Strings bestehen:

for i in Mirco Boris Christian
  do echo "Hallo $i"
done

Und schon begrüßt uns die Shell in drei separaten Zeilen mit Namen - Danke, Hallo Bash. Wichtig ist in diesem Konstrukt die Variable i, die natürlich nicht i heißen muss, das ist nur das Standardbeispiel. Darüber sprecht Ihr jedenfalls das Element des jeweiligen Durchlaufs an. Überhaupt, gewöhnt Euch am besten schon jetzt gute Variablennamen an:

for vorname in Mirco Boris Christian
  do echo "Hallo $vorname"
done

Das ist doch wesentlich verständlicher, oder?

Die Kommandos sind trivial, da steht Euch die ganze Bandbreite zur Verfügung - wie Ihr das jeweilige Element ansprecht wisst Ihr ja nun. Interessanter ist die Menge. Eine typische Frage ist: Wie lasse ich eine Schleife X mal durchlaufen? Eine mögliche Antwort:

for ziffer in $(seq 1 10)
  do echo Es ist Ziffer $ziffer
done

Das Tool seq gibt schlicht Sequenzen aus, hier also 1 bis 10, was entsprechend 10 Durchläufe ergibt. Wie wäre es mal mit einem Praxisbeispiel:

for dokument in $(ls dateien/dokumente/*.txt)
  cp $dokument /media/usb/backups/
done

Hier besteht die Menge also aus allen TXT-Dateien, die ls im Ordner gefunden hat. Dann wird jede Datei separat in einen Backup-Ordner kopiert - und schon habt Ihr eine erste wirklich nützliche Stapelverarbeitung.

In der Regel führen for-Schleifen ein Kommando mehrmals mit unterschiedlichen Optionen oder Daten aus. Es geht aber auch umgekehrt:

for prg in echo cowsay
  do $prg "Hallo Welt"
done

In diesem Fall würde also der Text "Hallo Welt" von den Programmen echo und cowsay ausgegeben. Nützlich wäre das vielleicht zum Vergleichen von Ausgabeformaten.

Bonus: X-kleiner-als-Schleifen

Hier noch ganz kurz ein paar Beispiele für die gängigen So-lange-X-kleiner-als-10-ist-Schleifen. Zunächst mit while:

x=0
while [[ $x -lt 10 ]]
  do echo $x ist kleiner als 10.
  ((x++))
done

Die Bedingung läuft hier über die doppelten eckigen Klammern, die einen Vergleichstest durchführen (es ist einer alternative Schreibweise für das Kommando "test"); -lt steht hier für lesser than/weniger als. Und das Hochzählen erledigt die doppelte runde Klammer, in der ++ wie üblich für +1 steht.

Statt der eckigen Klammern ginge auch die reguläre test-Schreibweise:

x=0
while $(test $x -lt 10)
  do echo $x ist kleiner als 10.
  ((x++))
done

$(test ...) und [[...]] ist exakt dasselbe.

Mit until:

x=0
until [[ $x -eq 10 ]]
  do echo $x ist kleiner als 10.
  ((x++))
done

Nur der Vergleichsoperator hat sich verändert, hier ist es jetzt -eq für equals/gleich.

Und jetzt mit for:

for (( x=0 ; x<10 ; x++ ))
  do echo $x ist kleiner als 10.
done

Bei for läuft es etwas eleganter: In der doppelten runden Klammer stehen drei Ausdrücke, genauer gesagt arithmetische Ausdrücke. Die ersten beiden formulieren Bedingungen, die dritte eine Operation, sofern die Bedingungen erfüllt sind. Scheiss Wordpress: Der zweite Ausdruck ist x kleiner als 10 - aber das behämmerte Wordpress kriegt es nicht auf die Reihe, die spitze Auf-Klammer für kleiner-als zu setzen ... stattdessen ersetzt es automatisch mit dem was da steht - DAS wiederum kann ich hier außerhalb eines Code-Blocks nicht wiederholen, weil daraus automatisch die spitze Klammer würde ... Richtig wäre - im "Inline-Code-Block" geht das nämlich: x<10

Falls Ihr übrigens die Hilfen zu Schleifen sucht: Eigene Manuals und Hilfe-Ausgaben haben sie nicht, als Bestandteile der Bash sind sie aber im Bash-Manual dokumentiert, also:

man bash

So, genug für etwas, das sich Basics schimpft. Vielleicht heute mal keine weiteren CLI-Artikel lesen, sondern ... hmmm ... was fluffigeres ... vielleicht was zu einem klassischen Feminismus-Rätsel bei ChatGPT.

Mirco Lang

Freier Journalist, Exil-Sauerländer, (ziemlich alter) Skateboarder, Dipl.-Inf.-Wirt, Einzelhandelskaufmann, Open-Source-Nerd, Checkmk-Handbuchschreiber. Ex-Saturn'ler, Ex-Data-Becker'ler, Ex-BSI'ler. Computer-Erstkontakt: ca. 1982 - der C64 des großen Bruders eines Freunds. Wenn Ihr hier mehr über Open Source, Linux und Bastelkram lesen und Tutonaut unterstützen möchtet: Über Kaffeesponsoring via Paypal.freue ich mich immer. Schon mal im Voraus: Danke! Nicht verpassen: cli.help und VoltAmpereWatt.de. Neu: Mastodon

Ein Kommentar

  1. Bash-until ist für Programmierer etwas verwirrend, da es in den meisten anderen Programmiersprachen in sogenannten nachprüfenden Schleifen eingesetzt wird. In nachprüfenden Schleifen wird der Schleifenkörper mindestens ein Mal durchlaufen um nachher die Schleifenbedingung zu prüfen (tue-solange-bis). In Bash ist until jedoch eine vorprüfende Schleife. Dieser verwirrende Unterschied ist wohl auch der Grund, warum until auch selten verwendet wird. Ich konnte es bisher in keinem der Bash-Skripte aus den installierten Paketen finden, ganz im Gegensatz zu while.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Schaltfläche "Zurück zum Anfang"