Willkommen zum fünften Artikel unserer technischen Wiki-Serie über Bash-Programmierung!
In den vorherigen Artikeln hast du gelernt, wie du Skripte erstellst, mit Variablen arbeitest, Kontrollstrukturen verwendest und Funktionen schreibst. Heute lernst du, wie deine Skripte mit der Außenwelt kommunizieren können – durch Ein- und Ausgabe.
Wie wichtig ist die Ein- und Ausgabe?
Ein Skript, das nicht mit seiner Umgebung kommunizieren kann, ist wie ein Mensch ohne Sinne. Es braucht Möglichkeiten, Informationen aufzunehmen (Eingabe) und Ergebnisse mitzuteilen (Ausgabe).
In Bash gibt es verschiedene Wege, dies zu tun:
- Eingaben von der Tastatur lesen
- Text auf dem Bildschirm ausgeben
- Daten in Dateien speichern
- Informationen aus Dateien lesen
Lass uns mit der einfachsten Form der Ausgabe beginnen – dem Anzeigen von Text auf dem Bildschirm.
Text ausgeben mit echo
Der echo
-Befehl ist dein wichtigstes Werkzeug für die Ausgabe.
Du hast ihn bereits in den vorherigen Artikeln kennengelernt:
#!/bin/bash
# Einfache Textausgabe
echo "Hallo, willkommen zu Ein- und Ausgabe in Bash!"
# Variablen ausgeben
name="Max"
echo "Hallo $name"
# Mehrere Zeilen ausgeben
echo "Erste Zeile"
echo "Zweite Zeile"
Erweiterte Ausgabemöglichkeiten
Der echo-Befehl mit Formatierung
Der echo
-Befehl kann mehr als nur einfachen Text ausgeben.
Mit der Option -e
kannst du spezielle Formatierungen verwenden:
#!/bin/bash
# Neue Zeile mit \n
echo -e "Erste Zeile\nZweite Zeile"
# Tabulator mit \t
echo -e "Name:\tMax\nAlter:\t25"
# Text hervorheben
echo -e "\033[1mFett\033[0m"
echo -e "\033[31mRot\033[0m"
echo -e "\033[44mBlauer Hintergrund\033[0m"
Formatierte Ausgabe mit printf
Für noch mehr Kontrolle über das Ausgabeformat gibt es den printf
-Befehl:
#!/bin/bash
# Grundlegende printf-Syntax
printf "Hallo, %s!\n" "Max"
# Zahlen formatieren
printf "Nummer: %d\n" 42
printf "Preis: %.2f €\n" 9.99
# Tabelle erstellen
printf "%-10s %5s %8s\n" "Name" "Alter" "Stadt"
printf "%-10s %5d %8s\n" "Max" 25 "Berlin"
printf "%-10s %5d %8s\n" "Anna" 30 "Hamburg"
Wichtig für Anfänger:
%s
ist ein Platzhalter für Text (Strings)%d
ist für ganze Zahlen%f
ist für Dezimalzahlen\n
erzeugt eine neue Zeile- Die Zahl nach
%
bestimmt die Feldbreite -
links-bündig statt rechts-bündig.2
bei%.2f
gibt die Anzahl der Dezimalstellen an
Benutzereingaben einlesen
Der read
-Befehl ist dein Werkzeug, um Eingaben von der Tastatur zu lesen.
Lass uns verschiedene Möglichkeiten kennenlernen:
Einfache Eingabe
#!/bin/bash
# Grundlegende Verwendung von read
echo "Wie heißt du?"
read name
echo "Hallo $name!"
# Mit eigener Eingabeaufforderung
read -p "Wie alt bist du? " alter
echo "Du bist also $alter Jahre alt."
Sichere Eingabe mit Überprüfung
#!/bin/bash
# Eingabe mit Überprüfung
while true; do
read -p "Gib eine Zahl zwischen 1 und 10 ein: " zahl
# Prüfe, ob die Eingabe eine Zahl ist
if ! [[ $zahl =~ ^[0-9]+$ ]]; then
echo "Fehler: Bitte nur Zahlen eingeben!"
continue
fi
# Prüfe den Wertebereich
if [ $zahl -lt 1 ] || [ $zahl -gt 10 ]; then
echo "Fehler: Die Zahl muss zwischen 1 und 10 liegen!"
continue
fi
echo "Danke! Du hast $zahl eingegeben."
break
done
Verschiedene read-Optionen
#!/bin/bash
# Zeitlimit für die Eingabe
read -t 5 -p "Du hast 5 Sekunden Zeit zu antworten: " antwort
if [ -z "$antwort" ]; then
echo -e "\nZeit abgelaufen!"
fi
# Passwort eingeben (ohne Anzeige)
read -s -p "Passwort eingeben: " passwort
echo -e "\nDanke für die Eingabe!"
# Mehrere Werte einlesen
read -p "Gib drei Zahlen ein (durch Leerzeichen getrennt): " zahl1 zahl2 zahl3
echo "Du hast eingegeben: $zahl1, $zahl2 und $zahl3"
Wichtige read-Optionen:
-p
zeigt eine Eingabeaufforderung-s
versteckt die Eingabe (für Passwörter)-t
setzt ein Zeitlimit in Sekunden-n
begrenzt die Anzahl der einzulesenden Zeichen-r
verhindert, dass Backslash als Escape-Zeichen interpretiert wird
Arbeiten mit Dateien
In Bash gibt es verschiedene Möglichkeiten, mit Dateien zu arbeiten.
Lass uns die wichtigsten Methoden kennenlernen:
Aus Dateien lesen
#!/bin/bash
# Eine Datei zeilenweise lesen
echo "Inhalt der Datei zeilenweise lesen:"
while IFS= read -r zeile; do
echo "$zeile"
done < "beispiel.txt"
# Kompletten Inhalt auf einmal lesen
inhalt=$(<beispiel.txt)
echo -e "\nKompletter Inhalt:"
echo "$inhalt"
# Bestimmte Zeilen lesen
echo -e "\nNur die erste Zeile:"
head -n 1 beispiel.txt
echo -e "\nNur die letzte Zeile:"
tail -n 1 beispiel.txt
In Dateien schreiben
#!/bin/bash
# Neue Datei erstellen oder überschreiben
echo "Das ist die erste Zeile" > neue_datei.txt
echo "Das ist die zweite Zeile" >> neue_datei.txt
# Mehrere Zeilen auf einmal schreiben
cat > mehrere_zeilen.txt << EOF
Zeile 1: Hallo
Zeile 2: Das ist ein Test
Zeile 3: Bash ist toll
EOF
# Inhalt anzeigen
echo "Inhalt der neuen Datei:"
cat neue_datei.txt
echo -e "\nInhalt der mehrere_zeilen.txt:"
cat mehrere_zeilen.txt
Wichtige Operatoren:
>
überschreibt eine Datei>>
hängt an eine Datei an<
liest aus einer Datei<<EOF
ermöglicht Mehrzeilen-Eingabe (Here-Document)
Dateien überprüfen
#!/bin/bash
dateiname="test.txt"
# Prüfe, ob Datei existiert
if [ -f "$dateiname" ]; then
echo "Die Datei existiert"
# Prüfe Lese- und Schreibrechte
if [ -r "$dateiname" ]; then
echo "Die Datei ist lesbar"
fi
if [ -w "$dateiname" ]; then
echo "Die Datei ist beschreibbar"
fi
else
echo "Die Datei existiert nicht"
fi
Wichtige Dateitests:
-f
prüft, ob eine reguläre Datei existiert-d
prüft, ob ein Verzeichnis existiert-r
prüft Leserechte-w
prüft Schreibrechte-x
prüft Ausführungsrechte-s
prüft, ob die Datei nicht leer ist
Ein- und Ausgabe umleiten
In Bash kannst du die Standardeingabe, -ausgabe und Fehlerausgabe umleiten. Das ist besonders nützlich für die Automatisierung und Protokollierung.
Grundlegende Umleitungen
#!/bin/bash
# Ausgabe in Datei umleiten
echo "Das geht in eine Datei" > ausgabe.txt
# Fehlerausgabe umleiten
ls nicht_existierende_datei 2> fehler.txt
# Beide Ausgaben in verschiedene Dateien umleiten
ls existiert_nicht alle_dateien 1> normal.txt 2> fehler.txt
# Beide Ausgaben in dieselbe Datei umleiten
ls -la &> alle_ausgaben.txt
Wichtige Umleitungsoperatoren:
1>
oder>
– Standardausgabe umleiten2>
– Fehlerausgabe umleiten&>
– beide Ausgaben umleiten>>
– an Datei anhängen statt überschreiben<
– Eingabe aus Datei lesen
Pipes verwenden
Mit Pipes (|
) kannst du die Ausgabe eines Befehls als Eingabe für einen anderen Befehl verwenden:
#!/bin/bash
# Zähle Zeilen in einer Datei
cat beispiel.txt | wc -l
# Finde bestimmte Wörter und zähle sie
echo "Apfel Banane Apfel Orange Apfel" | grep -o "Apfel" | wc -l
# Sortiere und zeige nur eindeutige Einträge
echo -e "Zeile 1\nZeile 2\nZeile 1" | sort | uniq
Praktisches Beispiel
Logfile-Verarbeitung
#!/bin/bash
# Funktion zum Protokollieren
protokolliere() {
local nachricht="$1"
local zeitstempel=$(date "+%Y-%m-%d %H:%M:%S")
# Protokolliere in Datei und zeige auf Bildschirm
echo "[$zeitstempel] $nachricht" | tee -a protokoll.txt
}
# Beispielverwendung
protokolliere "Skript gestartet"
# Fehler protokollieren
if ! ls nicht_existierend 2>/dev/null; then
protokolliere "Fehler: Datei nicht gefunden"
fi
protokolliere "Skript beendet"
# Zeige das Protokoll
echo -e "\nInhalt des Protokolls:"
cat protokoll.txt
Wichtige Befehle für die Verarbeitung:
grep
– Suchen nach Textsort
– Sortieren von Zeilenuniq
– Doppelte Zeilen entfernenwc
– Zeilen/Wörter/Zeichen zählentee
– Ausgabe in Datei und auf Bildschirm
Übung
Erstelle ein Adressbuch-Skript, das folgende Anforderungen erfüllt:
- Das Skript soll:
- Kontakte hinzufügen können
- Kontakte anzeigen können
- Nach Kontakten suchen können
- Alle Daten in einer Datei speichern
- Für jeden Kontakt sollen:
- Name
- Telefonnummer
- E-Mail-Adresse
gespeichert werden
- Beachte:
- Überprüfe alle Eingaben auf Gültigkeit
- Speichere die Daten strukturiert
- Behandle mögliche Fehler
Hier ist eine mögliche Lösung:
#!/bin/bash
# Konfiguration
ADRESSBUCH="adressbuch.txt"
# Kontakt hinzufügen
kontakt_hinzufuegen() {
# Eingaben sammeln
read -p "Name: " name
read -p "Telefon: " telefon
read -p "E-Mail: " email
# Eingaben überprüfen
if [ -z "$name" ] || [ -z "$telefon" ] || [ -z "$email" ]; then
echo "Fehler: Alle Felder müssen ausgefüllt werden"
return 1
fi
# E-Mail-Format prüfen (einfache Prüfung)
if ! [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Fehler: Ungültige E-Mail-Adresse"
return 1
fi
# In Datei speichern
echo "$name;$telefon;$email" >> "$ADRESSBUCH"
echo "Kontakt wurde gespeichert"
}
# Kontakte anzeigen
kontakte_anzeigen() {
if [ ! -f "$ADRESSBUCH" ]; then
echo "Keine Kontakte vorhanden"
return
fi
echo "=== Adressbuch ==="
while IFS=';' read -r name telefon email; do
echo "Name: $name"
echo "Telefon: $telefon"
echo "E-Mail: $email"
echo "----------------"
done < "$ADRESSBUCH"
}
# Nach Kontakten suchen
kontakt_suchen() {
read -p "Suchbegriff eingeben: " suche
if [ ! -f "$ADRESSBUCH" ]; then
echo "Keine Kontakte vorhanden"
return
fi
echo "=== Suchergebnisse ==="
grep -i "$suche" "$ADRESSBUCH" | while IFS=';' read -r name telefon email; do
echo "Name: $name"
echo "Telefon: $telefon"
echo "E-Mail: $email"
echo "----------------"
done
}
Fazit
In diesem fünften Teil unseres Bash-Grundkurses hast du gelernt, wie deine Skripte mit der Außenwelt kommunizieren können. Du kennst jetzt die verschiedenen Möglichkeiten der Ein- und Ausgabe in Bash, von einfachen Bildschirmausgaben bis hin zur Dateiverarbeitung. Du weißt, wie du Benutzereingaben einliest, diese überprüfst und wie du Daten dauerhaft in Dateien speicherst.
Die Fähigkeit, Ein- und Ausgabe zu verarbeiten, ist fundamental für jedes Bash-Skript. Mit diesem Wissen kannst du nun interaktive Skripte schreiben, Daten verarbeiten und Ergebnisse speichern.
Im nächsten Teil unserer Serie werden wir uns mit der Fehlerbehandlung und dem Debugging in Bash beschäftigen. Du wirst lernen, wie du deine Skripte robuster machst und Probleme effektiv findest und behebst.
Bis dahin, happy scripting!