EMZETT.
Login

Kurz: for i in {1..5}; do printf “%d ” “i"; done; echo for i in {10..0..5}; do printf "%d " "i”; done; echo

Teil des Kurses Bash

Kapitel 4 von 13 im Kurs Bash. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

for über eine Liste

for farbe in rot grün blau; do
    echo "Farbe: $farbe"
done
 
for i in {1..5}; do printf "%d " "$i"; done; echo
for i in {10..0..5}; do printf "%d " "$i"; done; echo
 
for ((i = 0; i < 3; i++)); do echo "Zähler $i"; done     # C-Stil
 
summe=0
for n in 1 2 3 4; do summe=$((summe + n)); done
echo "Summe: $summe"

Ausgabe:

Farbe: rot
Farbe: grün
Farbe: blau
1 2 3 4 5
10 5 0
Zähler 0
Zähler 1
Zähler 2
Summe: 10

Über Dateien

Nutze Globs, niemals for f in $(ls) (zerbricht bei Leerzeichen):

cd "$(mktemp -d)"
touch "a b.txt" c.txt d.md
for datei in *.txt; do
    echo "Datei: [$datei] hat $(wc -c < "$datei") Bytes"
done
for datei in *.nix; do
    [[ -e $datei ]] || { echo "keine .nix-Dateien"; break; }
done

Ausgabe:

Datei: [a b.txt] hat 0 Bytes
Datei: [c.txt] hat 0 Bytes
keine .nix-Dateien

while und until

n=3
while [[ $n -gt 0 ]]; do
    echo "n=$n"
    ((n--))
done
 
i=0
until [[ $i -ge 3 ]]; do
    echo "i=$i"
    ((i++))
done

Ausgabe:

n=3
n=2
n=1
i=0
i=1
i=2

Zeilen lesen

while read verarbeitet Eingaben zeilenweise. Setze IFS= und -r, damit nichts verändert wird:

printf "Mia 17\nTom 25\nZoe 31\n" | while IFS=' ' read -r name alter; do
    echo "$name ist $alter"
done
 
while IFS=, read -r land hauptstadt; do
    echo "$hauptstadt ist die Hauptstadt von $land"
done <<'DATEN'
Deutschland,Berlin
Frankreich,Paris
DATEN
 
mapfile -t zeilen < <(printf "eins\nzwei\ndrei\n")
echo "${#zeilen[@]} Zeilen, zweite: ${zeilen[1]}"

Ausgabe:

Mia ist 17
Tom ist 25
Zoe ist 31
Berlin ist die Hauptstadt von Deutschland
Paris ist die Hauptstadt von Frankreich
3 Zeilen, zweite: zwei

Achtung

In befehl | while read ... läuft die Schleife in einer Unter-Shell; Variablen, die du darin setzt, sind danach weg. Nutze stattdessen while ...; done < <(befehl).

zaehler=0
printf "a\nb\nc\n" | while read -r x; do ((zaehler++)); done
echo "mit Pipe: $zaehler"
zaehler=0
while read -r x; do ((zaehler++)); done < <(printf "a\nb\nc\n")
echo "mit Prozess-Ersetzung: $zaehler"

Ausgabe:

mit Pipe: 0
mit Prozess-Ersetzung: 3

break, continue, select

for i in {1..10}; do
    (( i % 2 == 0 )) && continue      # gerade überspringen
    (( i > 7 )) && break               # abbrechen
    printf "%d " "$i"
done
echo
 
for i in 1 2; do
    for j in a b c; do
        [[ $j == b ]] && continue 2    # äußere Schleife fortsetzen
        echo "$i$j"
    done
done

Ausgabe:

1 3 5 7
1a
2a

Muster: Wiederholen bis es klappt

versuch=0
max=3
until (( versuch >= max )); do
    ((versuch++))
    echo "Versuch $versuch"
    if (( versuch == 2 )); then echo "geklappt"; break; fi
done

Ausgabe:

Versuch 1
Versuch 2
geklappt

Merke

  • for x in liste; do ... done, Bereiche {1..10}, C-Stil ((i=0;i<n;i++))
  • Dateien per Glob (*.txt), nicht per $(ls)
  • while/until mit Bedingung; while IFS= read -r zeile; do ... done < datei
  • Pipe in while läuft in einer Unter-Shell: Prozess-Ersetzung < <(...) nutzen
  • break und continue (auch mit Ebenenzahl)

Übungsaufgabe

Gib alle Zahlen von 1 bis 30 aus, ersetze Vielfache von 3 durch “Fizz”, von 5 durch “Buzz”.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Bedingungen und Tests

Weiter: Funktionen und Argumente

Alle Kapitel: Bash im Überblick