Grundlagen der Shell-Skripterstellung

ShellBeginner
Jetzt üben

Einführung

Ein Shell-Skript speichert Befehle in einer Datei, sodass sich eine Aufgabe zuverlässig und einheitlich wiederholen lässt. Gute Skripte für Einsteiger legen den Interpreter ausdrücklich fest, setzen Variablenerweiterungen in Anführungszeichen, prüfen Eingaben vor der Verarbeitung und geben einen Exit-Status zurück, den andere Befehle auswerten können.

In diesem Labor erstellen Sie schrittweise kleine Bash-Skripte. Sie führen Skripte über Bash und als ausführbare Dateien aus, verwenden Variablen und Positionsargumente, lesen interaktive Eingaben ein, verzweigen mit if und Dateitests, wählen Exit-Codes, durchlaufen Dateien mit for und verbinden diese Konzepte in einem einfachen Protokoll-Zusammenfasser.

Das erste Skript erstellen und ausführen

In diesem Schritt erstellen Sie ein Bash-Skript, führen es über einen Interpreter aus und machen es direkt ausführbar.

Wechseln Sie in den Arbeitsbereich des Labors:

cd /home/labex/project/shell-lab

Erstellen Sie hello.sh mit einem Here-Dokument. Die erste Zeile ist ein Shebang, der Bash auswählt, wenn die Datei direkt ausgeführt wird:

cat > hello.sh <<'EOF'
#!/bin/bash

echo "Hello from a Bash script"
pwd
EOF

Sehen Sie sich die Datei vor der Ausführung an:

cat hello.sh

Übergeben Sie die Datei ausdrücklich an Bash. Das funktioniert auch dann, wenn noch keine Ausführungsrechte gesetzt sind:

bash hello.sh

Fügen Sie Ausführungsrechte hinzu und prüfen Sie den Dateimodus:

chmod u+x hello.sh
ls -l hello.sh

Führen Sie die Datei aus dem aktuellen Verzeichnis aus. ./ gibt einen Pfad an; die Shell durchsucht das aktuelle Verzeichnis normalerweise nicht automatisch:

./hello.sh

Variablen verwenden und sicher in Anführungszeichen setzen

In diesem Schritt weisen Sie Variablen Werte zu, erweitern sie und sehen, warum doppelte Anführungszeichen Werte mit Leerzeichen schützen.

Erstellen Sie ein Skript mit zwei Variablen:

cat > variables.sh <<'EOF'
#!/bin/bash

course="Linux for Noobs"
workspace="/home/labex/project/shell-lab"

echo "Course: $course"
echo "Workspace: $workspace"
printf 'Quoted argument count: %s\n' "$#"
printf 'First argument: %s\n' "${1:-not provided}"
EOF

Bei einer Variablenzuweisung dürfen keine Leerzeichen um = stehen. Doppelte Anführungszeichen ermöglichen die Erweiterung von $course und sorgen gleichzeitig dafür, dass Linux for Noobs als ein einziger Wert behandelt wird.

Führen Sie das Skript mit einem Argument aus, das Leerzeichen enthält:

bash variables.sh "beginner learner"

Die spezielle Variable $# enthält die Anzahl der Positionsargumente, während $1 das erste Argument bezeichnet. ${1:-not provided} verwendet einen Ersatzwert, wenn das Argument fehlt.

Speichern Sie die Ausgabe zur späteren Prüfung:

bash variables.sh "beginner learner" > variable-output.txt
cat variable-output.txt

Positionsargumente prüfen

In diesem Schritt verlangen Sie ein Argument, geben eine Verwendungshilfe aus und liefern bei Fehlern und Erfolg unterschiedliche Exit-Statuswerte zurück.

Erstellen Sie greet-argument.sh:

cat > greet-argument.sh <<'EOF'
#!/bin/bash

if [ "$#" -ne 1 ]; then
  echo "Usage: $0 NAME" >&2
  exit 2
fi

name=$1
echo "Hello, $name"
exit 0
EOF

Der Testbefehl [ ... ] prüft, ob die Anzahl der Argumente nicht gleich eins ist. >&2 sendet den Verwendungshinweis an die Standardfehlerausgabe, und exit 2 meldet eine ungültige Verwendung.

Führen Sie das Skript ohne Argument aus und geben Sie anschließend sofort $? aus, also den Exit-Status des vorherigen Befehls:

bash greet-argument.sh
echo "missing argument status: $?"

Der erwartete Status ist 2. Führen Sie das Skript nun korrekt aus:

bash greet-argument.sh "Ada Lovelace"
echo "valid argument status: $?"

Speichern Sie die erfolgreiche Begrüßung:

bash greet-argument.sh "Ada Lovelace" > argument-greeting.txt

Interaktive Eingaben lesen

In diesem Schritt fordern Sie eine Eingabe an, lesen eine Zeile sicher ein und behandeln leere Eingaben.

Erstellen Sie ask-name.sh:

cat > ask-name.sh <<'EOF'
#!/bin/bash

read -r -p "Enter your name: " name

if [ -z "$name" ]; then
  echo "A name is required" >&2
  exit 1
fi

echo "Welcome, $name"
EOF

read -r liest eine Zeile ein, ohne Backslashes speziell zu behandeln. -p zeigt eine Eingabeaufforderung an, und -z prüft, ob der Wert in Anführungszeichen leer ist.

Führen Sie das Skript aus:

bash ask-name.sh

Geben Sie an der Eingabeaufforderung Folgendes ein:

Grace Hopper

Sie sollten Welcome, Grace Hopper sehen. Für ein reproduzierbares gespeichertes Ergebnis können Sie eine Eingabezeile an dasselbe Skript weiterleiten:

printf 'Grace Hopper\n' | bash ask-name.sh > interactive-greeting.txt
cat interactive-greeting.txt

Mit Dateitests verzweigen

In diesem Schritt verwenden Sie if, elif und else zusammen mit Dateitests, um einen Pfad zu klassifizieren.

Erstellen Sie classify-path.sh:

cat > classify-path.sh <<'EOF'
#!/bin/bash

path=${1:-}

if [ -z "$path" ]; then
  echo "Usage: $0 PATH" >&2
  exit 2
elif [ -d "$path" ]; then
  echo "directory: $path"
elif [ -f "$path" ]; then
  echo "file: $path"
else
  echo "missing: $path" >&2
  exit 1
fi

exit 0
EOF

-d prüft, ob ein Verzeichnis vorliegt, und -f, ob es sich um eine reguläre Datei handelt. Die Reihenfolge ist wichtig: Eine ungültige Verwendung wird vor der Prüfung des Pfadtyps behandelt.

Testen Sie alle drei möglichen Ergebnisse:

bash classify-path.sh logs
bash classify-path.sh notes.txt
bash classify-path.sh missing.txt
echo "missing path status: $?"

Speichern Sie erfolgreiche Ergebnisse gemeinsam. && führt den zweiten Befehl nur aus, wenn der erste erfolgreich war:

bash classify-path.sh logs > path-results.txt && bash classify-path.sh notes.txt >> path-results.txt
cat path-results.txt

Mehrere Dateien mit einer For-Schleife verarbeiten

In diesem Schritt durchlaufen Sie Protokolldateien und zählen die passenden Einträge in jeder Datei.

Erstellen Sie count-errors.sh:

cat > count-errors.sh <<'EOF'
#!/bin/bash

log_dir=${1:-logs}

if [ ! -d "$log_dir" ]; then
  echo "Log directory not found: $log_dir" >&2
  exit 1
fi

for log_file in "$log_dir"/*.log; do
  error_count=$(grep -c '^ERROR ' "$log_file" || true)
  printf '%s errors=%s\n' "$(basename "$log_file")" "$error_count"
done
EOF

Die Schleife weist log_file bei jeder Iteration einen passenden Pfad zu. Die Anführungszeichen um "$log_file" schützen Pfade mit Leerzeichen, während basename den Verzeichnisprefix entfernt. grep -c zählt passende Zeilen; || true verhindert, dass keine Treffer einen größeren Ablauf mit strenger Fehlerbehandlung abbrechen.

Führen Sie die Schleife aus und speichern Sie ihre Ausgabe:

bash count-errors.sh logs | tee error-counts.txt

Für jede .log-Datei sollte ein Ergebnis angezeigt werden.

Prüfungen, Schleifen und Exit-Status kombinieren

In diesem Schritt erstellen Sie ein wiederverwendbares Skript, das ein Verzeichnis prüft, seine Protokolle zusammenfasst und Erfolg oder Fehlschlag eindeutig meldet.

Erstellen Sie summarize-logs.sh:

cat > summarize-logs.sh <<'EOF'
#!/bin/bash

input_dir=${1:-}
output_file=${2:-}

if [ -z "$input_dir" ] || [ -z "$output_file" ]; then
  echo "Usage: $0 INPUT_DIR OUTPUT_FILE" >&2
  exit 2
fi

if [ ! -d "$input_dir" ]; then
  echo "Input directory not found: $input_dir" >&2
  exit 1
fi

: > "$output_file"

for log_file in "$input_dir"/*.log; do
  lines=$(wc -l < "$log_file")
  errors=$(grep -c '^ERROR ' "$log_file" || true)
  printf '%s lines=%s errors=%s\n' "$(basename "$log_file")" "$lines" "$errors" >> "$output_file"
done

echo "Wrote summary to $output_file"
exit 0
EOF

Der Befehl : > "$output_file" erstellt die Zieldatei sicher oder leert sie, bevor die Schleife beginnt. Führen Sie das Skript mit beiden erforderlichen Argumenten aus:

chmod u+x summarize-logs.sh
./summarize-logs.sh logs log-summary.txt
echo "summary status: $?"
cat log-summary.txt

Testen Sie den Fehlerfall mit einem nicht vorhandenen Verzeichnis:

./summarize-logs.sh missing log-summary.txt
echo "missing directory status: $?"

Der Erfolgsstatus sollte 0 betragen, während der Status für das fehlende Verzeichnis 1 sein sollte.

Zusammenfassung

Sie haben Bash-Skripte erstellt und ausgeführt, Shebangs und Dateiberechtigungen verwendet, Variablen in Anführungszeichen erweitert, Positionsargumente und interaktive Eingaben gelesen und aussagekräftige Exit-Statuswerte zurückgegeben. Außerdem haben Sie mit if/elif/else verzweigt, Dateien und Verzeichnisse geprüft, Protokolle mit for durchlaufen und die Konzepte in einem wiederverwendbaren Zusammenfassungsprogramm kombiniert.

Diese Grundlagen machen spätere Automatisierungen übersichtlicher, sicherer wiederholbar und für andere Befehle oder geplante Aufgaben leichter auswertbar.