Willkommen zum siebten und letzten Artikel unserer technischen Wiki-Serie über Bash-Programmierung!
In den vorherigen Artikeln hast du die Grundlagen der Bash-Programmierung kennengelernt. Heute werden wir dein Wissen erweitern und dir fortgeschrittene Techniken zeigen, die deine Skripte noch leistungsfähiger machen.
In diesem Artikel lernst du drei wichtige fortgeschrittene Konzepte kennen:
- Arrays zur Verwaltung mehrerer Werte
- Reguläre Ausdrücke für die Textverarbeitung
- Verarbeitung von Kommandozeilenargumenten mit getopts
Diese Techniken werden dir helfen, komplexere Skripte zu schreiben und Daten effektiver zu verarbeiten.
Arrays in Bash
Arrays sind wie Container, in denen du mehrere Werte unter einem Namen speichern kannst. Sie sind besonders nützlich, wenn du mit Listen von Elementen arbeiten musst.
#!/bin/bash
# Ein Array erstellen
fruechte=("Apfel" "Banane" "Kirsche")
# Auf einzelne Elemente zugreifen
echo "Erste Frucht: ${fruechte[0]}"
echo "Zweite Frucht: ${fruechte[1]}"
# Alle Elemente ausgeben
echo "Alle Früchte: ${fruechte[@]}"
# Anzahl der Elemente
echo "Anzahl Früchte: ${#fruechte[@]}"
Arbeiten mit Arrays
Arrays bieten viele Möglichkeiten zur Datenmanipulation. Hier sind einige nützliche Techniken:
Elemente hinzufügen und entfernen
#!/bin/bash
# Array initialisieren
tiere=("Hund" "Katze" "Maus")
# Element hinzufügen
tiere+=("Elefant")
echo "Tiere nach Hinzufügen: ${tiere[@]}"
# Element an bestimmter Position hinzufügen
tiere[4]="Giraffe"
echo "Tiere nach Einfügen: ${tiere[@]}"
# Element entfernen
unset tiere[2]
echo "Tiere nach Entfernen: ${tiere[@]}"
Über Arrays iterieren
#!/bin/bash
farben=("Rot" "Grün" "Blau" "Gelb")
# Mit for-Schleife
echo "Farben mit for-Schleife:"
for farbe in "${farben[@]}"; do
echo "- $farbe"
done
# Mit Indexen
echo "Farben mit Indexen:"
for i in "${!farben[@]}"; do
echo "$i: ${farben[$i]}"
done
Arrays sortieren und filtern
#!/bin/bash
zahlen=(5 2 8 1 9 3)
# Array sortieren
sortierte_zahlen=($(printf '%s\n' "${zahlen[@]}" | sort -n))
echo "Sortierte Zahlen: ${sortierte_zahlen[@]}"
# Array filtern (nur gerade Zahlen)
gerade_zahlen=()
for zahl in "${zahlen[@]}"; do
if (( zahl % 2 == 0 )); then
gerade_zahlen+=("$zahl")
fi
done
echo "Gerade Zahlen: ${gerade_zahlen[@]}"
Assoziative Arrays (Bash 4+)
Assoziative Arrays erlauben es dir, Schlüssel-Wert-Paare zu speichern:
#!/bin/bash
# Assoziatives Array erstellen
declare -A hauptstaedte
hauptstaedte["Deutschland"]="Berlin"
hauptstaedte["Frankreich"]="Paris"
hauptstaedte["Italien"]="Rom"
# Zugriff auf Werte
echo "Die Hauptstadt von Deutschland ist ${hauptstaedte["Deutschland"]}"
# Alle Schlüssel ausgeben
echo "Länder: ${!hauptstaedte[@]}"
# Über assoziatives Array iterieren
for land in "${!hauptstaedte[@]}"; do
echo "$land: ${hauptstaedte[$land]}"
done
Arrays sind besonders nützlich, wenn du mit Datensätzen oder Listen arbeiten musst. Sie helfen dir, deinen Code übersichtlicher und effizienter zu gestalten.
Reguläre Ausdrücke
Reguläre Ausdrücke, oft als RegEx abgekürzt, sind leistungsstarke Werkzeuge zur Textverarbeitung. Sie ermöglichen es dir, komplexe Muster in Texten zu finden, zu überprüfen und zu manipulieren.
Grundlagen der regulären Ausdrücke
#!/bin/bash
# Einfache Mustersuche
if [[ "Hallo Welt" =~ Welt ]]; then
echo "Muster 'Welt' gefunden"
fi
# Verwendung von Metazeichen
if [[ "abc123" =~ ^[a-z]+[0-9]+$ ]]; then
echo "Buchstaben gefolgt von Zahlen"
fi
# Gruppierung und Alternativen
if [[ "Katze" =~ (Hund|Katze|Maus) ]]; then
echo "Ein Haustier gefunden"
fi
Verwendung mit grep
#!/bin/bash
validiere_email() {
local email="$1"
local regex="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$"
if [[ $email =~ $regex ]]; then
echo "Gültige E-Mail-Adresse"
return 0
else
echo "Ungültige E-Mail-Adresse"
return 1
fi
}
# Beispielaufruf
validiere_email "benutzer@example.com"
validiere_email "ungueltig@.com"
Textmanipulation mit sed
sed ist ein Stream-Editor, der reguläre Ausdrücke für Textmanipulationen nutzt:
#!/bin/bash
# Ersetze alle Vorkommen von 'alt' durch 'neu'
echo "Das ist ein alter Text" | sed 's/alt/neu/g'
# Entferne alle Leerzeilen aus einer Datei
sed '/^$/d' datei.txt
# Füge Zeilennummern hinzu
sed = datei.txt | sed 'N;s/\n/. /'
Reguläre Ausdrücke sind ein mächtiges Werkzeug, aber sie können komplex werden. Es lohnt sich, Zeit in das Erlernen und Üben zu investieren, da sie in vielen Bereichen der Textverarbeitung und Datenanalyse nützlich sind.
Kommandozeilenargumente
In professionellen Skripten möchtest du oft verschiedene Optionen und Parameter verarbeiten. Der getopts-Befehl hilft dir dabei, dies strukturiert zu tun.
Grundlegende Verwendung von getopts
#!/bin/bash
# Standardwerte setzen
verbose=0
datei=""
name=""
# Optionen verarbeiten
while getopts "vf:n:" option; do
case $option in
v) # Verbose-Modus
verbose=1
;;
f) # Dateiname
datei="$OPTARG"
;;
n) # Name
name="$OPTARG"
;;
?) # Ungültige Option
echo "Ungültige Option: -$OPTARG"
exit 1
;;
esac
done
# Verwendung der Optionen
[ $verbose -eq 1 ] && echo "Verbose-Modus aktiviert"
[ -n "$datei" ] && echo "Datei: $datei"
[ -n "$name" ] && echo "Name: $name"
Verwendung des Skripts:
./skript.sh -v -f config.txt -n "Max Mustermann"
Erweiterte Argumentverarbeitung
Bash
#!/bin/bash
usage() {
echo "Verwendung: $0 [-h] [-v] [-f DATEI] [-n NAME]"
echo "Optionen:"
echo " -h Diese Hilfe anzeigen"
echo " -v Verbose-Modus aktivieren"
echo " -f Datei angeben"
echo " -n Namen angeben"
exit 1
}
# Standardwerte
verbose=0
datei=""
name=""
# Optionen verarbeiten
while getopts ":hvf:n:" opt; do
case $opt in
h)
usage
;;
v)
verbose=1
;;
f)
if [ ! -f "$OPTARG" ]; then
echo "Fehler: Datei '$OPTARG' existiert nicht" >&2
exit 1
fi
datei="$OPTARG"
;;
n)
name="$OPTARG"
;;
:)
echo "Option -$OPTARG benötigt ein Argument" >&2
exit 1
;;
\?)
echo "Ungültige Option: -$OPTARG" >&2
usage
;;
esac
done
# Verbleibende Argumente verarbeiten
shift $((OPTIND-1))
rest_args=("$@")
# Verarbeitung
if [ $verbose -eq 1 ]; then
echo "Konfiguration:"
echo "- Verbose: Ja"
[ -n "$datei" ] && echo "- Datei: $datei"
[ -n "$name" ] && echo "- Name: $name"
[ ${#rest_args[@]} -gt 0 ] && echo "- Weitere Argumente: ${rest_args[*]}"
fi
🔧 Praktisches Beispiel
Backup-Skript mit Optionen
#!/bin/bash
# Standardwerte
backup_dir="/tmp/backup"
compress=0
verbose=0
# Hilfefunktion
show_help() {
cat << EOF
Backup-Skript
Verwendung: $0 [-c] [-v] [-d VERZEICHNIS] QUELLE
Optionen:
-c Backup komprimieren
-v Ausführliche Ausgaben
-d Backup-Verzeichnis angeben
EOF
}
# Optionen verarbeiten
while getopts ":hcvd:" opt; do
case $opt in
h)
show_help
exit 0
;;
c)
compress=1
;;
v)
verbose=1
;;
d)
backup_dir="$OPTARG"
;;
:)
echo "Option -$OPTARG benötigt ein Argument" >&2
exit 1
;;
\?)
echo "Ungültige Option: -$OPTARG" >&2
show_help
exit 1
;;
esac
done
# Verbleibende Argumente verarbeiten
shift $((OPTIND-1))
if [ $# -eq 0 ]; then
echo "Fehler: Keine Quelle angegeben" >&2
show_help
exit 1
fi
source_dir="$1"
Erweiterte Bash-Features
Prozess-Substitution
Mit Prozess-Substitution kannst du die Ausgabe von Befehlen wie eine temporäre Datei behandeln:
#!/bin/bash
# Vergleiche den Inhalt zweier Verzeichnisse
diff <(ls dir1) <(ls dir2)
# Erkärung:
# <(befehl) erstellt eine temporäre "Datei" mit der Ausgabe des Befehls
# Nützlich wenn ein Befehl eine Datei als Eingabe erwartet,
# du aber die Ausgabe eines anderen Befehls verwenden möchtest
Arithmetische Erweiterung
Bash kann direkt mit mathematischen Ausdrücken arbeiten:
#!/bin/bash
# Grundlegende Arithmetik
echo "Addition: $((5 + 3))"
echo "Multiplikation: $((4 * 3))"
echo "Division: $((10 / 2))"
echo "Modulo (Rest): $((7 % 3))"
# Komplexere Berechnungen
basis=5
hoehe=3
flaeche=$((basis * hoehe))
echo "Fläche: $flaeche"
# Inkrement/Dekrement
zaehler=0
((zaehler++)) # Erhöhe um 1
((zaehler--)) # Verringere um 1
Parameter-Expansion
Parameter-Expansion bietet mächtige Möglichkeiten zur Variablenmanipulation:
#!/bin/bash
name="Max Mustermann"
# Standardwerte setzen
echo "Name ist: ${name:-Unbekannt}" # Verwendet 'Unbekannt' wenn $name leer ist
leerer_wert=""
echo "Wert ist: ${leerer_wert:-Standard}" # Zeigt 'Standard'
# Teilstrings extrahieren
echo "Erste 3 Buchstaben: ${name:0:3}" # Zeigt 'Max'
echo "Ab Position 4: ${name:4}" # Zeigt 'Mustermann'
# Text ersetzen
echo "Einmal ersetzen: ${name/Max/Moritz}" # Ersetzt das erste 'Max'
echo "Alle ersetzen: ${name//a/A}" # Ersetzt alle 'a' durch 'A'
# Länge einer Variable
echo "Länge des Namens: ${#name}" # Zeigt die Anzahl der Zeichen
# Großbuchstaben/Kleinbuchstaben
echo "Großbuchstaben: ${name^^}" # Konvertiert zu Großbuchstaben
echo "Kleinbuchstaben: ${name,,}" # Konvertiert zu Kleinbuchstaben
Here-Strings
Here-Strings ermöglichen es dir, Text direkt als Eingabe für Befehle zu verwenden:
#!/bin/bash
# Suche in einem Text
grep "Muster" <<< "Dies ist ein Muster-Text"
# Mehrere Zeilen verarbeiten
while read -r zeile; do
echo "Zeile: $zeile"
done <<< "Erste Zeile
Zweite Zeile
Dritte Zeile"
# Nützlich für kleine Textmengen, die du nicht in einer Datei speichern möchtest
Indirekte Referenzen
Mit indirekten Referenzen kannst du Variablennamen dynamisch verwenden:
Bash
#!/bin/bash
# Variablen definieren
name="Max"
alter="30"
beruf="Entwickler"
# Variable indirekt referenzieren
feldname="name"
echo "Wert von $feldname ist: ${!feldname}" # Zeigt den Wert von $name
# Praktisches Beispiel
for feld in name alter beruf; do
echo "$feld: ${!feld}"
done
Diese erweiterten Features machen Bash zu einer mächtigen Skriptsprache. Sie helfen dir, komplexere Aufgaben elegant zu lösen und deinen Code effizienter zu gestalten.
Übung
Erstelle ein Skript zur Verwaltung einer einfachen Kontaktdatenbank, das alle fortgeschrittenen Techniken verwendet, die wir gelernt haben:
Das Skript soll:
- Kontakte in einem Array speichern
- Reguläre Ausdrücke zur Validierung von Eingaben verwenden
- Kommandozeilenargumente mit getopts verarbeiten
- Das Hinzufügen, Suchen und Auflisten von Kontakten unterstützen
Anforderungen:
- Verwende assoziative Arrays für Kontakte
- Validiere E-Mail-Adressen und Telefonnummern mit RegEx
- Implementiere verschiedene Suchmöglichkeiten
- Speichere Kontakte in einer Datei
- Behandle alle Fehler ordnungsgemäß
Hier ist eine mögliche Lösung:
#!/bin/bash
# Konfiguration
KONTAKT_DATEI="kontakte.txt"
declare -A kontakte
# Hilfefunktion
zeige_hilfe() {
cat << EOF
Kontakt-Manager
Verwendung: $0 [-h] [-a] [-s SUCHE] [-l]
Optionen:
-h Diese Hilfe anzeigen
-a Neuen Kontakt hinzufügen
-s Kontakte suchen
-l Alle Kontakte auflisten
EOF
exit 0
}
# E-Mail validieren
validiere_email() {
local email="$1"
local regex="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
[[ $email =~ $regex ]]
}
# Kontakt hinzufügen
kontakt_hinzufuegen() {
read -p "Name: " name
read -p "E-Mail: " email
read -p "Telefon: " telefon
if ! validiere_email "$email"; then
echo "Fehler: Ungültige E-Mail-Adresse" >&2
return 1
fi
kontakte["$name"]="$email;$telefon"
echo "$name:$email:$telefon" >> "$KONTAKT_DATEI"
echo "Kontakt erfolgreich hinzugefügt"
}
# Kontakte suchen
kontakte_suchen() {
local suche="$1"
while IFS=: read -r name email telefon; do
if [[ "$name" =~ $suche ]] || [[ "$email" =~ $suche ]]; then
echo "Name: $name"
echo "E-Mail: $email"
echo "Telefon: $telefon"
echo "---------------"
fi
done < "$KONTAKT_DATEI"
}
# Alle Kontakte auflisten
kontakte_auflisten() {
if [ ! -f "$KONTAKT_DATEI" ]; then
echo "Keine Kontakte gefunden"
return 0
fi
echo "Alle Kontakte:"
echo "============="
while IFS=: read -r name email telefon; do
echo "Name: $name"
echo "E-Mail: $email"
echo "Telefon: $telefon"
echo "---------------"
done < "$KONTAKT_DATEI"
}
# Optionen verarbeiten
while getopts ":hals:" opt; do
case $opt in
h)
zeige_hilfe
;;
a)
kontakt_hinzufuegen
;;
l)
kontakte_auflisten
;;
s)
kontakte_suchen "$OPTARG"
;;
\?)
echo "Ungültige Option: -$OPTARG" >&2
zeige_hilfe
;;
esac
done
# Wenn keine Optionen angegeben wurden, zeige Hilfe
if [ $OPTIND -eq 1 ]; then
zeige_hilfe
fi