Grundlagen der Shell-Skripterstellung

ShellBeginner
Jetzt üben

Einführung

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

In diesem Lab 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 aus, arbeiten mit for-Schleifen und verbinden diese Konzepte in einem einfachen Log-Zusammenfasser.

Erstes 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 das Arbeitsverzeichnis des Labs:

cd /home/labex/project/shell-lab

Erstellen Sie hello.sh mit einem Here-Dokument. Die erste Zeile ist ein Shebang. Er legt Bash fest, wenn Sie die Datei direkt ausführen:

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

echo "Hello from a Bash script"
pwd
EOF

Sehen Sie sich die Datei an, bevor Sie sie ausführen:

cat hello.sh

Übergeben Sie die Datei ausdrücklich an Bash. Das funktioniert auch, bevor Sie die Ausführungsberechtigung hinzufügen:

bash hello.sh

Fügen Sie die Ausführungsberechtigung hinzu und prüfen Sie den Modus:

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 quoten

In diesem Schritt weisen Sie Variablen Werte zu, expandieren 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 in der Shell keine Leerzeichen um = stehen. Doppelte Anführungszeichen ermöglichen die Expansion von $course und halten Linux for Noobs gleichzeitig als einen einzigen Wert zusammen.

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, und $1 ist das erste Argument. ${1:-not provided} liefert einen Ersatzwert, wenn das erste Argument fehlt.

Speichern Sie die Ausgabe zur 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 Nutzungshilfe aus und verwenden unterschiedliche Exit-Status für Fehler und Erfolg.

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 Nutzungstext an die Standardfehlerausgabe, und exit 2 meldet eine ungültige Verwendung.

Führen Sie das Skript ohne Argument aus und zeigen Sie anschließend sofort $? an, 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 sicher eine Zeile ein und behandeln eine leere Eingabe.

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 leiten Sie eine Eingabezeile in dasselbe Skript weiter:

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 vorhanden ist, 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 Logdateien und zählen die passenden Datensätze 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 Leerzeichen, während basename das Verzeichnispräfix entfernt. grep -c zählt passende Zeilen. || true verhindert, dass keine Treffer einen größeren strikten Ablauf abbrechen.

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

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

Sie sollten für jede .log-Datei ein Ergebnis sehen.

Prüfung, Schleifen und Exit-Status kombinieren

In diesem Schritt erstellen Sie ein wiederverwendbares Skript, das ein Verzeichnis prüft, seine Logs 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 das Ziel sicher oder leert es vor Beginn der Schleife. 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 Fehlerpfad mit einem nicht vorhandenen Verzeichnis:

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

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

Zusammenfassung

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

Diese Grundlagen machen spätere Automatisierung leichter lesbar, sicherer erneut ausführbar und für andere Befehle oder geplante Jobs einfacher auswertbar.