Grundlagen der Shellskripterstellung

Fasse Befehlsfolgen, die du immer wieder eingibst, zu Bash-Skripten zusammen. Beginne jedes Skript mit einer Shebang-Zeile und mache es ausführbar. Speichere Werte in Variablen, schütze sie mit Quoting und erfasse Befehlsausgaben. Melde Erfolg und Fehlschlag mit Rückgabecodes und prüfe Dateien, Text und Zahlen, um über die nächsten Schritte zu entscheiden. Wiederhole Abläufe mit for-, while- und until-Schleifen und übergib Argumente, damit ein Skript viele Fälle abdeckt. Plane schließlich die automatische Ausführung deiner Skripte mit cron oder systemd-Timern und prüfe, ob jeder Lauf erfolgreich war.

AnfängerEinheit 4 von 7 in Kurs: Linux – Befehlszeile, Shellskripte und Systemverwaltung

Was du lernst

  1. Fasse eine Befehlsfolge, die du immer wieder eingibst, in einer Skriptdatei zusammen, beginne sie mit der richtigen Interpreterzeile und führe sie aus jedem Verzeichnis aus.
    • Wiederkehrende Befehle in einer Skriptdatei zusammenfassen
      Schreibe Befehle der Reihe nach in eine reine Textdatei, ergänze Kommentare und beginne die Datei mit einer Shebang-Zeile, die Bash als Interpreter nennt.
    • Ein Skript ausführen und seinen Speicherort wählen
      Mache ein Skript ausführbar, führe es über einen Pfad oder einen Interpreter aus, lege es in einem Verzeichnis auf dem PATH ab und erkenne, wann es deine aktuelle Shell ändern kann.
  2. Speichere Text, Zahlen und Befehlsausgaben in Variablen, lies Benutzereingaben ein und verwende Quoting, damit Leerzeichen und Sonderzeichen unverändert bei Befehlen ankommen.
    • Variablen anlegen, auslesen und exportieren
      Weise Shellvariablen Werte zu und verwende sie, wähle gute Namen, lies Benutzereingaben ein und übergib Variablen an die Programme, die ein Skript startet.
    • Wörter, Variablen und Sonderzeichen mit Quoting schützen
      Entscheide dich zwischen einfachen und doppelten Anführungszeichen und Backslashes und schütze jede Variablenexpansion mit Quoting, damit Leerzeichen und Platzhalter in Werten einen Befehl nicht stören können.
    • Befehlsausgaben erfassen und mit ganzen Zahlen rechnen
      Speichere die Ausgabe eines Befehls mit Befehlssubstitution und rechne mit ganzen Zahlen, um zum Beispiel Dateinamen mit Datum zu bilden und Zähler zu führen.
  3. Lies und setze den Rückgabestatus von Befehlen und Skripten, verkette Befehle abhängig von Erfolg oder Fehlschlag und finde und stoppe Fehler, bevor sie Schaden anrichten.
    • Rückgabecodes auslesen, setzen und zur Befehlsverkettung nutzen
      Nutze den Rückgabestatus, den jeder Befehl liefert, beende ein Skript mit einem aussagekräftigen Code und führe Befehle nur aus, wenn ein vorheriger Befehl erfolgreich war oder fehlgeschlagen ist.
    • Fehler finden und ein Skript sicher beenden
      Prüfe ein Skript und verfolge seinen Ablauf, um Fehler zu finden, sende Fehlermeldungen an die Standardfehlerausgabe und lasse das Skript bei Fehlschlägen, nicht gesetzten Variablen und fehlgeschlagenen Pipelines anhalten.
  4. Prüfe Dateien, Text und Zahlen, wähle mit if und case Aktionen aus und wiederhole Befehle für Listen, Dateien und Zeilen mit for-, while- und until-Schleifen.
    • Dateien, Zeichenketten und Zahlen prüfen
      Schreibe Bedingungen mit test, [ ] und [[ ]], die prüfen, ob Dateien existieren, und Text sowie ganze Zahlen vergleichen. Verknüpfe oder negiere diese Bedingungen.
    • Aktionen mit if, elif, else und case auswählen
      Führe mit if, elif und else abhängig von einer Bedingung verschiedene Befehle aus und gleiche mit case einen Wert mit mehreren Mustern ab.
    • Befehle mit for für Listenelemente und Dateien wiederholen
      Durchlaufe eine Liste von Wörtern, die auf ein Muster passenden Dateien, einen Zahlenbereich oder die Argumente eines Skripts und gehe mit Dateinamen um, die Leerzeichen enthalten.
    • Befehle mit while und until wiederholen, bis sich eine Bedingung ändert
      Führe Befehle aus, solange eine Bedingung erfüllt ist oder bis sie erfüllt ist, lies eine Datei zeilenweise und steuere Schleifen mit break, continue und sleep.
  5. Übergib einem Skript seine Eingaben über die Befehlszeile, lies die Argumente im Skript, prüfe sie und lege Standardwerte fest, damit dasselbe Skript für viele Fälle funktioniert.
    • Positionsparameter und Argumentanzahl auslesen
      Lies mit $0, $1 bis $9, ${10}, $# und "$@" die Wörter aus, die nach dem Namen eines Skripts angegeben werden, und arbeite sie mit shift ab.
    • Argumente prüfen, Aufrufhinweise anzeigen und Standardwerte festlegen
      Prüfe Anzahl und Art der Argumente, gib einen Aufrufhinweis aus und beende das Skript mit einem Fehlercode, verwende Standardwerte und verarbeite einfache Optionen.
  6. Führe Skripte mit cron oder systemd-Timern zu festen Zeiten oder in festen Abständen aus, ohne angemeldet zu sein, und prüfe, ob die geplanten Läufe stattfinden und erfolgreich sind.
    • Aufgaben mit cron zeitlich planen
      Schreibe Crontab-Einträge mit den fünf Zeitfeldern, bearbeite sie mit crontab und liste sie damit auf. Bereite Skripte auf die minimale Umgebung von cron vor.
    • Aufgaben mit systemd-Timern zeitlich planen
      Kombiniere eine Service-Unit mit einer Timer-Unit, schreibe kalenderbasierte und intervallbasierte Zeitpläne, aktiviere den Timer und prüfe den nächsten Lauf und die Protokolle.

Shellskripterstellung einfach erklärt

6 Kapitel

1

Deine ersten Bash-Skripte schreiben und ausführen

Einige Befehle lassen sich leichter wiederholen, wenn sie zusammen in einem Skript stehen. Du legst Bash als Interpreter für die Datei fest, hältst ihre Anweisungen lesbar und wählst, wie du sie startest. Dateirechte, Suchpfade für Befehle und Kind-Shells erklären einige häufige Überraschungen: warum ein Skript mit bash funktioniert, aber mit ./ fehlschlägt, warum sein Name nicht gefunden wird und warum seine Verzeichniswechsel das Verzeichnis deines Terminals nicht ändern.

1.1 Wiederkehrende Befehle in einer Skriptdatei zusammenfassen

Ein Shellskript speichert eine Befehlsfolge in einer reinen Textdatei. Bash liest die Befehle der Reihe nach, genau wie die Befehle, die du an einer Eingabeaufforderung eingibst. Ein Skript kann eine Aufgabe wiederholen, ohne dass jemand jeden Schritt eintippt, und bietet dir eine zentrale Stelle, um die Aufgabe zu korrigieren oder zu verbessern.

Den Interpreter in die erste Zeile setzen

Der Shebang teilt Linux mit, welches Programm ein ausführbares Skript lesen soll. Beginne ein Bash-Skript mit #!/bin/bash. Die Zeichen #! müssen die ersten beiden Zeichen der Datei sein: Davor dürfen keine Leerzeichen und keine Leerzeile stehen. Bash steht für Bourne Again Shell. Sie wird unter Linux häufig als interaktive Shell genutzt und liest auch Skriptdateien.

Ein Interpreter ist ein Programm, das eine andere Sprache liest und ausführt. Derselbe Mechanismus ermöglicht es, mit #!/usr/bin/python3 Python oder mit #!/usr/bin/awk -f awk auszuwählen. Der Rest eines Bash-Skripts muss Shellbefehle enthalten, die Bash versteht.

Erstelle backup-notes.sh in einem Editor für reinen Text wie nano oder vi:

#!/bin/bash
# Keep a copy of the notes and show the backup folder.
mkdir -p ~/backup
cp ~/notes.txt ~/backup/
ls -l ~/backup

Bash legt zuerst das Zielverzeichnis an, kopiert dann die Notizen und listet anschließend das Ziel auf. mkdir -p ist auch erfolgreich, wenn das Verzeichnis bereits existiert, sodass ein späterer Lauf es wiederverwenden kann. Die Quelldatei ~/notes.txt muss existieren, damit das Kopieren funktioniert. Durch das Speichern der Befehle wird diese Quelldatei nicht angelegt.

Die Datei für Menschen lesbar machen

Die zweite Zeile ist ein Kommentar. Außerhalb von durch Quoting geschütztem Text beginnt # am Anfang eines Wortes einen Kommentar; Bash ignoriert den Rest der Zeile. Beschreibe in Kommentaren den Zweck eines Schrittes, etwa warum eine Sicherung aufbewahrt werden muss. Leerzeilen und Einrückungen machen Befehlsgruppen leichter erkennbar. Rücke einheitlich ein, wenn du Bedingungen und Schleifen hinzufügst.

Die Endung .sh hilft beim Erkennen eines Shellskripts. Linux verlangt diese Endung nicht, und sie wählt weder Bash aus noch erteilt sie Ausführungsrecht. Eine Datei namens backup-notes kann dieselben Befehle ausführen.

Die Shell passend zur Sprache wählen
Erste ZeileAuswahl des Interpreters
#!/bin/bashVerwendet Bash unter dem festen Pfad /bin/bash.
#!/usr/bin/env bashVerwendet env, um Bash über PATH zu finden.
#!/bin/shVerwendet die sh des Systems, die eine andere Shell sein kann.

Unter Debian und Ubuntu wählt /bin/sh normalerweise dash aus. Bash-Funktionen wie [[ ... ]] schlagen dort fehl. Ein Bash-Skript braucht einen Bash-Interpreter, auch wenn einfache Befehle zufällig unter beiden Shells funktionieren. Der Dateiname something.sh behebt keinen unpassenden Shebang.

Ein Problem mit Zeilenenden erkennen

Windows-Editoren können vor jedem Zeilenvorschub einen Wagenrücklauf speichern. Unter Linux kann dieses unsichtbare Zeichen Teil des Shebang-Pfads werden. Ein Fehler wie /bin/bash^M: bad interpreter: No such file or directory weist auf dieses Problem hin, obwohl /bin/bash existiert.

Wandle die Datei mit dos2unix backup-notes.sh in Unix-Zeilenenden um und speichere künftige Skripte im Editor mit Unix-Zeilenenden. Die Befehle in der Datei können korrekt sein, während das zusätzliche Zeichen Linux daran hindert, ihren Interpreter zu starten.

Wichtige Erkenntnisse

  • Ein Skript ist reiner Text mit Befehlen, die der Reihe nach ausgeführt werden.
  • Der Shebang muss ganz am Anfang der Datei beginnen und den richtigen Interpreter nennen.
  • Verwende Kommentare und Einrückungen, um Zweck und Struktur deutlich zu machen.
  • Die Endung .sh ist eine Konvention; sie wählt keine Shell aus.
  • Unix-Zeilenenden verhindern, dass ein versteckter Wagenrücklauf den Shebang unbrauchbar macht.

1.2 Ein Skript ausführen und seinen Speicherort wählen

Bash kann ein Skript direkt lesen oder es kann als Programm gestartet werden. Diese Wege unterscheiden sich darin, welche Rechte sie benötigen und wie der Interpreter gewählt wird. Der eingegebene Pfad bestimmt außerdem, ob die Shell nach einem Befehl sucht oder eine bestimmte Datei verwendet.

Zwei Wege, dieselbe Datei zu starten
bash backup-notes.sh
chmod u+x backup-notes.sh
./backup-notes.sh

Der erste Befehl startet Bash und lässt sie die Datei lesen. Das Skript braucht Leserecht; sein eigenes Ausführungsbit ist nicht nötig. Bash behandelt den Shebang als Kommentar, weil der Interpreter bereits gewählt wurde.

Der zweite Befehl fügt für den Eigentümer der Datei Ausführungsrecht hinzu. In einer Rechtezeichenfolge wie -rwxr--r-- bedeutet das x des Eigentümers, dass die Datei ausführbar ist. Der dritte Befehl führt die Datei als Programm aus und verwendet ihren Shebang. Auch chmod +x ist gebräuchlich; ohne eine angegebene Berechtigungsklasse begrenzt die umask, welche Klassen Ausführungsrecht erhalten. chmod u+x richtet sich ausdrücklich an den Eigentümer.

Meldet ./backup-notes.sh „Permission denied“, prüfe das Ausführungsrecht und den Zugriff auf den Pfad. Wenn bash backup-notes.sh funktioniert, heißt das nicht, dass die nötigen Rechte für die direkte Ausführung vorliegen.

Die Befehlssuche verstehen

./ bedeutet das aktuelle Verzeichnis. Enthält ein Befehl einen Schrägstrich, folgt Bash diesem Pfad. Gibst du einen Namen ohne Schrägstrich ein, durchsucht Bash die Verzeichnisse in PATH. Das aktuelle Verzeichnis fehlt normalerweise in dieser Liste. Es reicht also nicht, im Verzeichnis eines Skripts zu sein, um es allein über seinen Namen auszuführen.

echo "$PATH"
command -v backup-notes.sh
type backup-notes.sh

PATH ist eine durch Doppelpunkte getrennte Liste, zum Beispiel /home/sam/.local/bin:/usr/local/bin:/usr/bin:/bin. Die erste passende ausführbare Datei wird verwendet. Die letzten beiden Befehle helfen zu erkennen, was bei einem Namen ausgeführt wird, auch wenn es sich um eine ältere Kopie an einer anderen Stelle auf dem PATH handelt.

Um ein persönliches Skript über seinen Namen verfügbar zu machen, lege es in einem Verzeichnis auf deinem PATH ab. Viele Distributionen fügen ~/bin oder ~/.local/bin bei der Anmeldung hinzu, wenn das Verzeichnis existiert; prüfe deinen tatsächlichen PATH. /usr/local/bin ist ein üblicher Speicherort für gemeinsam genutzte Skripte. Zum Schreiben dort sind Administratorrechte nötig.

Zwischen einer Kind-Shell und der aktuellen Shell wählen

./settings.sh oder bash settings.sh startet einen Bash-Kindprozess. Dessen Variablen und Verzeichniswechsel gehören zu diesem Kindprozess. Ein Skript mit cd /var/log ändert das Verzeichnis des Terminals nicht, von dem aus es gestartet wurde. Wenn es endet, befindest du dich im Terminal weiterhin im bisherigen Verzeichnis.

Beim Sourcing werden Befehle in die aktuelle Shell eingelesen:

source ./settings.sh
# Equivalent short form:
. ./settings.sh

Nutze dies für eine Einstellungsdatei, die deine Sitzung ändern soll. Sourcing benötigt Lese-, aber kein Ausführungsrecht, und ein Shebang startet keinen separaten Interpreter. Das Einlesen einer Bash-Einstellungsdatei setzt daher voraus, dass die aktuelle Shell Bash-Syntax versteht.

Das Ergebnis eines Laufs lesen

Unmittelbar nach dem Ende eines Skripts zeigt echo $? dessen Rückgabestatus. Sofern das Skript nicht exit mit einem gewählten Code verwendet, stammt sein Status vom letzten Befehl. Eine erfolgreiche abschließende Auflistung kann daher einen zuvor fehlgeschlagenen Kopiervorgang verbergen; spätere Fehlerprüfungen ermöglichen es dem Skript, das tatsächliche Ergebnis der Aufgabe zu melden.

Wichtige Erkenntnisse

  • bash file liest ein Skript mit Bash; ./file braucht Ausführungsrecht und verwendet den Shebang.
  • PATH wird nur bei Befehlsnamen ohne Schrägstrich durchsucht.
  • Prüfe einen Befehlsnamen mit command -v oder type.
  • Die Ausführung startet eine Kind-Shell; Sourcing kann die aktuelle Shell ändern.
2

Werte in Variablen speichern und sicher mit Quoting schützen

Variablen ermöglichen es, dieselben Befehle mit wechselnden Pfaden, Namen und Anzahlen zu verwenden. Quoting hält diese Werte zusammen, während Bash eine Befehlszeile aufbaut, sodass ein Leerzeichen in einem Namen Teil des Namens bleibt. Du liest Eingaben, übergibst Werte an Kindprozesse, erfasst Befehlsausgaben und rechnest mit ganzen Zahlen. Diese Bausteine wirken zusammen, wenn ein Skript einen Dateinamen mit Datum erstellt oder fortlaufend zählt.

2.1 Variablen anlegen, auslesen und exportieren

Eine Variable gibt einem Wert einen Namen, damit dasselbe Skript ihn wiederverwenden kann. Bash-Variablen enthalten normalerweise Text, auch wenn dieser wie eine Zahl aussieht. Du weist den Wert einmal zu und expandierst den Namen überall dort, wo ein Befehl diesen Wert benötigt.

Ohne Leerzeichen zuweisen
city=Lisbon
greeting="Good morning"
echo "$greeting from $city"

Die Ausgabe lautet „Good morning from Lisbon“. Um das Zuweisungszeichen = stehen keine Leerzeichen. Bei city = Lisbon behandelt Bash city als Befehl und die anderen Wörter als Argumente. Die Anführungszeichen um "Good morning" halten beide Wörter in einem Wert zusammen.

Verwende Buchstaben, Ziffern und Unterstriche in Variablennamen und beginne mit einem Buchstaben oder Unterstrich. Groß- und Kleinschreibung wird unterschieden: file, File und FILE sind verschieden. Wähle für skripteigene Werte kleingeschriebene Namen wie backup_dir. Das hilft zu vermeiden, dass Umgebungsvariablen wie PATH oder HOME überschrieben werden. Das Setzen von PATH=/data ändert die Befehlsauflösung und kann dazu führen, dass gewöhnliche Befehle nicht mehr gefunden werden.

Das Ende eines Namens markieren

Ein Dollarzeichen leitet eine Expansion ein. Geschweifte Klammern zeigen die Grenze, wenn unmittelbar weiterer Text folgt:

file=report
echo "${file}_old"

Dies gibt „report_old“ aus. Bei "$file_old" sucht Bash nach einer Variable namens file_old, nicht nach file gefolgt von _old. Ohne set -u wird ein nicht gesetzter Name zu leerem Text expandiert. Ein Schreibfehler kann daher einen leeren Pfad oder eine leere Meldung erzeugen, ohne sofort einen Fehler auszulösen.

Ein Wert wie count=5 speichert den Text „5“. Text neben einer Expansion bewirkt keine Berechnung: echo "$count+1" gibt „5+1“ aus. Die arithmetische Expansion gibt Zahlen eine andere Rolle, wenn Berechnungen nötig sind.

Eine Eingabezeile lesen
read -r -p "Your name: " name
echo "Hello, $name"

read speichert die eingegebene Zeile in name. -p gibt die Eingabeaufforderung vor und -r erhält Backslashes. Bei der Eingabe „Lee Kim“ lautet die Begrüßung „Hello, Lee Kim“. Ein Skript, das ohne anwesende Person läuft, benötigt seine Eingaben aus Argumenten, Dateien oder Standardwerten; eine Eingabeaufforderung kann einen fehlenden Wert nicht zuverlässig liefern.

Werte für Kindprozesse exportieren

Eine gewöhnliche Shellvariable gehört zu der Shell, in der sie gesetzt wurde. Durch Exportieren wird sie für die Aufnahme in die Umgebung markiert, die an die von dieser Shell gestarteten Programme kopiert wird:

export BACKUP_DIR=/mnt/usb
bash backup-notes.sh

Die Bash im Kindprozess kann nun BACKUP_DIR lesen. Weist der Kindprozess einen anderen Wert zu, behält der Elternprozess seinen eigenen Wert. Die Umgebung wird vom Eltern- an den Kindprozess vererbt; spätere Änderungen werden nicht zurückgesendet.

NameÜbliche Bedeutung
HOMEHome-Verzeichnis
USERBenutzername
PWDAktuelles Arbeitsverzeichnis
PATHVerzeichnisse, die nach Befehlsnamen durchsucht werden

env oder printenv zeigt Umgebungsvariablen an. unset name entfernt die Variable namens name; es weist keine leere Zeichenkette zu. Bei normaler Expansion können beide leer erscheinen, aber eine Prüfung auf nicht gesetzte Variablen kann eine fehlende von einer gesetzten Variable unterscheiden.

Wichtige Erkenntnisse

  • Zuweisungen verwenden name=value ohne Leerzeichen um =.
  • Bei Variablennamen wird Groß- und Kleinschreibung unterschieden; verwende für eigene Werte kleingeschriebene Namen.
  • ${name} markiert vor unmittelbar anschließendem Text das Ende eines Variablennamens.
  • read -r liest Eingaben und erhält dabei Backslashes.
  • Exportierte Werte werden an Kindprozesse kopiert, niemals zurück an einen Elternprozess.
  • unset entfernt eine Variable.

2.2 Wörter, Variablen und Sonderzeichen mit Quoting schützen

Bash liest einen Befehl, bevor das Programm seine Argumente erhält. Leerzeichen trennen Wörter und Zeichen wie *, ?, $, ;, &, |, < und > haben besondere Funktionen. Quoting steuert, welche dieser Funktionen aktiv bleiben.

Wählen, was expandiert werden soll
FormWas Bash tut
'fixed text'Erhält alles darin wörtlich.
"text with $name"Erhält Leerzeichen und Platzhalterzeichen, expandiert aber Variablen, Befehlsausgaben und arithmetische Ausdrücke.
\*Behandelt das nächste Zeichen außerhalb von Anführungszeichen wörtlich.

Vergleiche bei HOME=/home/sam:

echo 'Home: $HOME *'
echo "Home: \$HOME *"

Der erste Befehl gibt „Home: $HOME *“ aus. Der zweite gibt ebenfalls „Home: $HOME *“ aus. Das Sternchen bleibt in beiden Fällen wörtlich erhalten. Doppelte Anführungszeichen erlauben zwar die Expansion der Variable, aber der Backslash verhindert sie hier. Ein einfaches Anführungszeichen kann nicht unmittelbar innerhalb einer Zeichenkette in einfachen Anführungszeichen stehen.

Innerhalb doppelter Anführungszeichen können Backslashes ein Dollarzeichen, einen Backtick, ein doppeltes Anführungszeichen oder einen Backslash schützen. Zum Beispiel gibt echo "Price: \$5" die Ausgabe „Price: $5“ aus. Außerhalb von Anführungszeichen gibt echo 5 \* 3 die Ausgabe „5 * 3“ aus und touch my\ file.txt legt eine Datei mit einem Leerzeichen im Namen an.

Einen Wert ohne Quoting durch Bash verfolgen
file="my report.txt"
cp $file backup/

Zuerst expandiert Bash die Variable. Dann teilt die Wortaufteilung ihren Wert an Leerzeichen, Tabulatoren und Zeilenvorschüben. Der Befehl erhält my, report.txt und backup/ als separate Argumente. Er versucht, zwei Quelldateien statt der einen beabsichtigten Datei zu kopieren.

Enthält ein entstandenes Wort Platzhalterzeichen, ersetzt die Dateinamenexpansion es anschließend durch passende Dateinamen. Ein gespeicherter Wert *.txt kann bei einer Expansion ohne Quoting zu mehreren Dateiargumenten werden. Diese zusätzlichen Schritte erfolgen, bevor cp startet; das Programm kann die beabsichtigte Gruppierung nicht wiederherstellen.

cp "$file" backup/

Nun bleibt der expandierte Wert ein Argument: „my report.txt“. Bash entfernt die Anführungszeichen selbst; sie sind Anweisungen für die Auswertung und kein Teil des an cp übergebenen Pfads. Setze Variablenexpansionen und Befehlssubstitutionen in doppelte Anführungszeichen, wenn ihr vollständiger Wert zusammenbleiben soll.

Einen leeren Wert erhalten

Quoting ist auch wichtig, wenn ein Wert leer ist. In [ $answer = yes ] verschwindet ein leeres answer und hinterlässt einen ungültigen Test. [ "$answer" = yes ] übergibt eine leere Zeichenkette als ein Argument, sodass der Test gültig und falsch ist.

Dieselbe Gruppierungsregel gilt für wörtlich angegebene Wörter. mkdir new folder legt zwei Verzeichnisse an, während mkdir "new folder" eines anlegt. Das Quoting eines gesamten Pfads ist nützlich, unabhängig davon, ob sein Leerzeichen direkt eingegeben wurde oder aus einer Variable stammt.

Wörtlichen und expandierten Text verbinden

Benachbarte Teile in Anführungszeichen bilden ein Wort, wenn kein Leerzeichen sie trennt. Bei price=8 gibt echo 'Price: $'"$price" die Ausgabe „Price: $8“ aus. Der feste Teil steht in einfachen und der veränderliche Teil in doppelten Anführungszeichen. Ebenso lässt sich ein Suchmuster festhalten: grep 'cost: \$[0-9]' prices.txt übergibt sein Muster ohne Shell-Expansion, sodass grep das Muster interpretieren kann.

Wichtige Erkenntnisse

  • Einfache Anführungszeichen erhalten Text wörtlich; doppelte erlauben Expansionen und halten Werte zusammen.
  • Expansionen ohne Quoting durchlaufen die Wortaufteilung und anschließend die Dateinamenexpansion.
  • Anführungszeichen erhalten einen leeren Wert als Argument.
  • Ein Backslash kann ein Sonderzeichen wörtlich erhalten.
  • Benachbarte Teile in Anführungszeichen bilden ein Wort, wenn kein Leerzeichen sie trennt.

2.3 Befehlsausgaben erfassen und mit ganzen Zahlen rechnen

Befehle erzeugen häufig einen Wert, den ein anderer Schritt benötigt. Bash kann diese Ausgabe erfassen, in Text einsetzen oder für eine Berechnung verwenden. Befehlssubstitution und arithmetische Expansion haben ähnliche Satzzeichen, erfüllen aber unterschiedliche Aufgaben.

Die Standardausgabe erfassen
today=$(date +%F)
cp notes.txt "notes-${today}.txt"

$(...) führt einen Befehl aus und ersetzt die Substitution durch dessen Standardausgabe. Am 2026-10-22 enthält today „2026-10-22“ und die Kopie heißt notes-2026-10-22.txt. Ein Datum in der Reihenfolge Jahr-Monat-Tag hält Dateinamen bei der Sortierung nach Namen in Datumsreihenfolge. Du kannst die Substitution auch direkt in den Namen setzen: "notes-$(date +%F).txt".

Zeilenvorschübe am Ende der erfassten Ausgabe werden entfernt. Auch die ältere Form mit Backticks erfasst Ausgaben, aber $(...) lässt sich leichter lesen und verschachteln. Setze eine als Befehlsargument verwendete Substitution wie "$(date +%F)" in doppelte Anführungszeichen, damit ihr Ergebnis zusammenbleibt.

Die Befehlssubstitution erfasst nur die Standardausgabe. Fehler auf der Standardfehlerausgabe gehen weiterhin an ihr übliches Ziel. result=$(some_command 2>&1) führt beide Ströme innerhalb der Erfassung zusammen, wenn das Skript dies benötigt. Würden Fehler mit einem Wert vermischt, der eine Zahl enthalten soll, schlüge eine spätere Berechnung fehl.

Eine Anzahl ohne Dateinamen erfassen
lines=$(wc -l < access.log)
echo "Lines: $lines"

Enthält die Datei 342 Zeilenvorschübe, liefert wc die Anzahl 342. Wird die Datei in wc umgeleitet, enthält dessen Ausgabe nur die Anzahl; wc -l access.log gibt außerdem den Dateinamen aus. Ein Ergebnis, das wie eine Zahl aussieht, kann anschließend wiederverwendet werden, sofern der Befehl erfolgreich war.

Mit ganzen Zahlen rechnen

$(( ... )) führt eine arithmetische Expansion aus:

echo "$(( 17 / 5 ))"
echo "$(( 17 % 5 ))"

Die Ergebnisse sind 3 und 2. Die Ganzzahldivision lässt den Rest entfallen; % liefert ihn. Für Addition, Subtraktion und Multiplikation werden +, - und * verwendet. Variablennamen können innerhalb des Ausdrucks ohne Dollarzeichen stehen: total=$(( price * qty )).

Bei a=5 gibt echo "$a+3" den Text „5+3“ aus. echo "$(( a + 3 ))" berechnet das Ergebnis und gibt 8 aus. Die zusätzlichen Klammern wählen die Arithmetik; $(a + 3) würde stattdessen versuchen, einen Befehl namens a auszuführen.

Ein Zähler beginnt mit einem Wert wie count=0 und wird mit count=$(( count + 1 )) aktualisiert. Bash bietet auch (( count++ )); dies ist ein arithmetischer Befehl mit eigenem Rückgabestatus, was in Skripten mit Fehleroptionen wichtig ist.

Die benötigte Genauigkeit erhalten

Die Bash-Arithmetik verwendet ganze Zahlen. 7 / 2 ergibt 3 und ein Dezimalwert wie 2.5 verursacht einen arithmetischen Syntaxfehler. Ein separates Werkzeug kann mit Dezimalzahlen rechnen:

echo "scale=2; 7 / 2" | bc

Dies ergibt 3.50. Multipliziere bei der Ganzzahlarithmetik vor dem Dividieren, wenn das Produkt einen noch benötigten Bruchteil erhält. Für 45 von 60 ergibt $(( 45 * 100 / 60 )) den Wert 75. Wird zuerst dividiert, ergibt 45 / 60 null, sodass $(( 45 / 60 * 100 )) null bleibt; der verlorene Bruchteil lässt sich durch spätere Multiplikation nicht zurückgewinnen.

Wichtige Erkenntnisse

  • $(command) erfasst die Standardausgabe und entfernt abschließende Zeilenvorschübe.
  • $((expression)) rechnet mit ganzen Zahlen.
  • Verwende / für die Ganzzahldivision und % für ihren Rest.
  • Ein Zähler speichert nach jeder Erhöhung seinen aktualisierten Wert.
  • Multiplizierst du vor dem Dividieren, kann das einen frühen Genauigkeitsverlust bei der Ganzzahlarithmetik verhindern.
  • Verwende ein Werkzeug wie bc, wenn ein Dezimalergebnis benötigt wird.
3

Erfolg und Fehlschlag mit Rückgabecodes melden

Ein Skript braucht ein Ergebnis, das sowohl Menschen als auch Programme verstehen können. Eine Ausgabe erklärt, was passiert ist, während ein Rückgabestatus einem anderen Befehl die Entscheidung ermöglicht, ob er fortfahren soll. Du speicherst diesen Status, prüfst voneinander abhängige Schritte und hältst Fehlschläge in Pipelines sichtbar. Syntaxprüfungen, Ablaufverfolgung und Fehleroptionen helfen, die Ursache eines fehlgeschlagenen Laufs zu finden, bevor spätere Befehle seine Auswirkungen schwerer erkennbar machen.

3.1 Rückgabecodes auslesen, setzen und zur Befehlsverkettung nutzen

Ein Befehl meldet sein Ergebnis auf zwei Arten: Er kann Text ausgeben und liefert einen Rückgabestatus. Programme entscheiden anhand dieses Status, was als Nächstes geschieht. Ein Skript kann eine beruhigende Meldung ausgeben und dennoch fehlgeschlagen sein oder nichts ausgeben und erfolgreich sein.

Einen Status lesen, bevor er sich ändert

Ein Rückgabestatus ist eine ganze Zahl von 0 bis 255. Null bedeutet Erfolg. Ein Wert ungleich null meldet einen Fehlschlag oder ein anderes dokumentiertes Ergebnis. grep verwendet zum Beispiel 0 für einen Treffer, 1 für keinen Treffer und 2 für einen Fehler. Eine Suche ohne Treffer kann für deine Aufgabe ein normales Ergebnis sein, obwohl ihr Status ungleich null ist.

$? enthält den Status des zuletzt ausgeführten Befehls:

grep -q root /etc/passwd
status=$?
echo "Search status: $status"

Die Zuweisung speichert das Ergebnis, bevor ein anderer Befehl es ersetzt. Bei ls /missing; echo $?; echo $? liefert GNU ls den Wert 2 für den unzugänglichen Befehlszeilenpfad. Das erste echo gibt 2 aus und ist dann erfolgreich. Das zweite gibt 0 aus, den Status dieses echo und nicht den der ursprünglichen Auflistung.

Mit einem nützlichen Ergebnis enden

exit 1 beendet ein Skript sofort und meldet seinem Aufrufer 1. exit 0 meldet Erfolg. Ein exit ohne Zahl verwendet den Status des vorherigen Befehls; wird das Ende normal erreicht, gilt der Status des letzten Befehls. Wähle Codes zwischen 0 und 255: exit 256 läuft auf 0 um und würde fälschlich Erfolg melden.

Einige Statuswerte stammen von Bash selbst:

CodeBedeutung
127Der Befehl wurde nicht gefunden.
126Der Befehl wurde gefunden, konnte aber nicht ausgeführt werden.
128 + nDer Befehl endete aufgrund des Signals mit der Nummer n.

Strg+C sendet Signal 2, daher meldet ein so beendeter Befehl üblicherweise 130. Auch gewöhnliche Programme dokumentieren ihre eigenen Codes; 1 und 2 haben nicht in allen Werkzeugen eine einheitliche Bedeutung.

Abhängige Befehle verketten
mkdir -p ~/backup && cp notes.txt ~/backup/
cd /data/reports || exit 1

&& führt den nächsten Befehl nur nach Erfolg aus. Hier hängt das Kopieren davon ab, dass das Sicherungsverzeichnis erstellt oder gefunden wird. || führt den nächsten Befehl nur nach einem Fehlschlag aus. Hier beendet ein fehlgeschlagener Verzeichniswechsel das Skript, bevor spätere Befehle das falsche Arbeitsverzeichnis verwenden.

true liefert 0; false liefert 1. Ein vorangestelltes ! kehrt Erfolg oder Fehlschlag eines Befehls um. ! grep -q ERROR app.log ist erfolgreich, wenn die Suche keine passende Zeile findet, allerdings auch, wenn grep mit einem Fehler fehlschlägt. Verwende ausdrückliche Statusprüfungen, wenn diese Ergebnisse unterschieden werden müssen.

Eine ganze Pipeline prüfen
grep ERROR missing.log | wc -l

Standardmäßig hat eine Pipeline den Status ihres letzten Befehls. grep schlägt wegen der fehlenden Datei fehl, aber wc liest einen leeren Strom, gibt 0 aus und ist erfolgreich. Der Status der Pipeline ist daher 0.

set -o pipefail lässt eine Pipeline fehlschlagen, wenn einer ihrer Befehle fehlschlägt. Sie meldet den Status ungleich null, der am weitesten rechts steht, oder 0, wenn alle Befehle erfolgreich sind. Dadurch werden Fehler früherer Befehle für if, &&, || und den Aufrufer sichtbar. Ein Zeitplaner kann dann einen erfolgreichen Bericht von einem unterscheiden, der seine Eingabe nie gelesen hat.

Wichtige Erkenntnisse

  • Rückgabestatus 0 bedeutet Erfolg; die Bedeutung von Ergebnissen ungleich null wird von jedem Programm dokumentiert.
  • Speichere $? sofort, wenn du den Wert nach einem weiteren Befehl benötigst.
  • exit liefert dem Aufrufer des Skripts ein Ergebnis.
  • && fährt nach Erfolg fort und || nach einem Fehlschlag.
  • Ohne pipefail meldet eine Pipeline nur den Status ihres letzten Befehls.

3.2 Fehler finden und ein Skript sicher beenden

Bash läuft normalerweise weiter, nachdem ein Befehl fehlgeschlagen ist. Hängt der nächste Befehl von dieser Arbeit ab, kann aus einem kleinen Fehler durch das Fortfahren ein größeres Problem werden. Prüfe abhängige Schritte ausdrücklich und finde anschließend mit Syntaxprüfung und Ablaufverfolgung heraus, warum ein Lauf anders als geplant verläuft.

Anhalten, bevor sich ein Fehler auswirkt
cd /backups || exit 1

Nun können die nachfolgenden Befehle nur nach einem erfolgreichen Verzeichniswechsel ausgeführt werden. Das ist vor Dateioperationen wichtig: Schlägt ein Verzeichniswechsel fehl und läuft das Skript weiter, beziehen sich relative Pfade weiterhin auf das alte Verzeichnis. Prüfe das Ziel, bevor du Befehle ausführst, die Dateien ändern oder löschen.

Eine Fehlermeldung und ein Fehlerstatus richten sich an unterschiedliche Empfänger:

echo "Error: $file not found" >&2
exit 1

Die Meldung geht an die Standardfehlerausgabe, sodass die Standardausgabe für Daten verfügbar bleibt. Bei ./report.sh > report.txt bleibt die Meldung im Terminal sichtbar, während die normale Ausgabe in die Datei gelangt. Der Status ungleich null ermöglicht einem anderen Programm, den Fehler zu erkennen, ohne den Satz zu lesen.

Syntax prüfen und dann den Ablauf verfolgen
BefehlWirkung
bash -n script.shLiest die Syntax, ohne Befehle auszuführen.
bash -x script.shFührt das Skript aus und gibt expandierte Befehle vor ihrer Ausführung aus.

Ein fehlendes fi, done oder schließendes Anführungszeichen ist ein Syntaxproblem. bash -n kann es finden, oft anhand einer Meldung wie „unexpected end of file“. Ein syntaktisch gültiger, aber falsch geschriebener Dateipfad muss bei der Ausführung geprüft werden.

Bei der Ablaufverfolgung wird Befehlen ein + vorangestellt. Eine Zeile wie cp "$src" "$dest" zeigt dabei die tatsächlich eingesetzten Pfade. set -x und set +x schalten die Ablaufverfolgung für einen Abschnitt ein und wieder aus.

Die Fehleroptionen verstehen

set -euo pipefail kombiniert drei Einstellungen:

  • -e beendet das Skript nach einem nicht behandelten Fehlschlag eines Befehls.
  • -u meldet eine nicht gesetzte Variable als Fehler.
  • pipefail sorgt dafür, dass sich fehlgeschlagene Pipeline-Befehle auf den Pipeline-Rückgabestatus auswirken.

-e lässt erwartete Fehlschläge in if-, while- und until-Bedingungen, bei negierten Befehlen und bei nicht letzten Befehlen in &&- oder ||-Listen zu. Ohne pipefail löst ein Fehlschlag vor dem letzten Pipeline-Befehl kein Beenden aus. Ausdrückliche Prüfungen bleiben nützlich, weil sie festlegen, was das Skript beim Fehlschlag eines bestimmten Schrittes tun soll.

Auch ein arithmetischer Befehl meldet wahr oder falsch. (( count++ )) liefert Status 1, wenn der alte Wert 0 ist. Eine nicht behandelte Verwendung unter -e kann das Skript daher stoppen, obwohl die Erhöhung stattgefunden hat. Die Zuweisung count=$(( count + 1 )) vermeidet diesen Status des arithmetischen Befehls.

-u fängt einen Tippfehler wie $filname ab, wenn nur filename gesetzt wurde. Eine Variable, die existiert, aber leer ist, wird nicht zurückgewiesen. ${dir:?not set} prüft bei dieser Expansion, ob dir fehlt oder leer ist. Ein erwartetes Ergebnis ohne Treffer lässt sich mit einem Test behandeln; command || true unterdrückt jeden Fehlschlag dieses Befehls. Verwende es daher nur, wenn alle diese Fehlschläge akzeptabel sind.

Meldungen lesen und aufräumen

„Command not found“ weist auf ein Problem mit einem Namen, einem installierten Programm oder PATH hin. „Permission denied“ weist auf ein Problem beim Ausführen oder Dateizugriff hin. „Unary operator expected“ entsteht häufig durch einen leeren Wert ohne Quoting in [ ]; „integer expression expected“ bedeutet, dass eine numerische Prüfung Text erhalten hat.

Ein EXIT-Trap richtet eine Aufräumaktion ein, zum Beispiel trap 'rm -f "$tmpfile"' EXIT, nachdem tmpfile ein Wert zugewiesen wurde. Der Befehl in Anführungszeichen läuft, wenn Bash endet, auch bei einem ausdrücklichen exit oder einem Fehlerabbruch unter -e. ShellCheck kann Skripte vor einem Lauf ebenfalls auf häufige Quoting- und Logikfehler prüfen.

Wichtige Erkenntnisse

  • Prüfe einen Schritt, bevor du Befehle ausführst, die von ihm abhängen.
  • Schreibe Diagnosemeldungen auf die Standardfehlerausgabe und melde einen Fehlschlag mit einem Status ungleich null.
  • bash -n prüft die Syntax; bash -x führt das Skript aus und verfolgt seinen Ablauf.
  • Bei geprüften Fehlschlägen gibt es Ausnahmen für set -e.
  • set -u fängt nicht gesetzte Variablen ab, während ${name:?message} auch leere Werte zurückweist.
  • Ein EXIT-Trap kann eine temporäre Datei entfernen, wenn das Skript endet.
4

Entscheidungen treffen und Abläufe wiederholen

Ein nützliches Skript wählt Aktionen aus und wiederholt sie für wechselnde Eingaben. Tests machen aus Fragen zu Dateien, Text und Zahlen einen Erfolg oder Fehlschlag. Zweige wählen eine Aktion aus, während Schleifen Befehle auf Listen anwenden oder weiterlaufen, bis sich eine Bedingung ändert. Du verfolgst den Wert jedes Durchlaufs und erhältst Leerzeichen, Datensätze und Zähler, während die Daten das Skript durchlaufen.

4.1 Dateien, Zeichenketten und Zahlen prüfen

Eine Bedingung in Bash ist ein Befehl, dessen Status wahr oder falsch bedeutet. Mit Tests kannst du Fragen zu Pfaden, Text und Zahlen stellen. Wähle einen Operator passend zur Art des Werts; dieselben ausgegebenen Zeichen können als Text und als Zahl unterschiedliche Bedeutungen haben.

Dem Test eigene Wörter geben

test -f notes.txt und [ -f notes.txt ] fragen, ob ein Pfad auf eine existierende reguläre Datei verweist. [ ist ein Befehl und sein letztes Argument muss ] sein. Leerzeichen trennen seine Argumente:

[ -f "$file" ]

Ohne das Leerzeichen nach [ sucht Bash möglicherweise nach einem Befehl namens [-f. In [ "$a"="$b" ] bilden die fehlenden Leerzeichen um = ein nicht leeres Wort. Der Test ist daher wahr, selbst wenn sich die Werte unterscheiden. Operatoren müssen separate Argumente sein.

Eine Dateiprüfung wählen
OperatorWahr, wenn der Pfad …
-eexistiert.
-feine existierende reguläre Datei ist.
-dein existierendes Verzeichnis ist.
-r, -w, -xfür den aktuellen Benutzer lesbar, beschreibbar beziehungsweise ausführbar ist.
-sexistiert und eine Größe über null hat.
-Lein symbolischer Link ist.

Bei einem Verzeichnis namens logs sind -e und -d erfolgreich, während -f fehlschlägt. Dateiprüfungen folgen einem symbolischen Link normalerweise bis zu seinem Ziel; -L prüft den Link selbst. Ein toter Link kann daher -L erfüllen und bei -e fehlschlagen.

Text oder ganze Zahlen vergleichen

Zeichenkettenprüfungen verwenden = und != für Gleichheit und Ungleichheit. -z prüft auf die Länge null und -n auf eine Länge ungleich null. [ "$answer" = yes ] trifft genau auf „yes“ zu; „Yes“ und „yes “ sind anderer Text. Doppelte Anführungszeichen erhalten einen leeren Wert im Test.

Ganzzahlvergleiche verwenden -eq, -ne, -lt, -le, -gt und -ge: gleich, ungleich, kleiner als, kleiner oder gleich, größer als und größer oder gleich. [ "$count" -gt 100 ] fragt, ob die Zahl 100 übersteigt.

[ 07 -eq 7 ]
[ 07 = 7 ]

Der numerische Vergleich ist erfolgreich, weil die Werte gleich sind. Der Zeichenkettenvergleich schlägt fehl, weil ein Text mit einer zusätzlichen Null beginnt.

Verwende innerhalb von [ ] kein bloßes > für einen numerischen Test. In [ 10 > 9 ] leitet Bash die Ausgabe in eine Datei namens 9 um und prüft das verbleibende nicht leere Wort. In [[ 10 < 9 ]] von Bash vergleicht der Operator Zeichenketten, sodass das erste Zeichen 1 vor 9 einsortiert wird. Verwende für numerische Vergleiche -lt oder -gt oder Bash-Arithmetik wie (( count > 100 )).

Bedingungen verknüpfen

[ ! -d "$dir" ] ist erfolgreich, wenn der Pfad kein existierendes Verzeichnis ist; er kann eine reguläre Datei sein oder fehlen. [ -f "$f" ] && [ -r "$f" ] ist nur erfolgreich, wenn beide Tests erfolgreich sind. Separate Tests, die mit || verbunden sind, sind erfolgreich, wenn mindestens einer erfolgreich ist.

Bash hat außerdem das Schlüsselwort für Bedingungen [[ ... ]]. Es verhindert die Wortaufteilung seiner Variablenexpansionen und erlaubt && und || innerhalb des Ausdrucks. Ein Muster ohne Quoting rechts von == führt einen Musterabgleich durch: [[ $file == *.log ]] trifft auf „app.log“ zu. Mit Quoting würde das Muster wörtlich behandelt. Diese Syntax benötigt Bash; dash unterstützt sie nicht.

Wichtige Erkenntnisse

  • Ein Test meldet wahr mit Status 0 und falsch mit Status 1.
  • Setze Leerzeichen um [ und seine Operatoren und schließe mit ] ab.
  • Dateiprüfungen unterscheiden Existenz, Typ und Zugriff.
  • Die Gleichheitsprüfung für Zeichenketten vergleicht Text; numerische Operatoren vergleichen ganzzahlige Werte.
  • Verwende -gt und -lt für Zahlen, keine bloßen Umleitungszeichen.
  • Eine Negation kehrt einen Test um; && verlangt beide Bedingungen.
  • [[ ... ]] von Bash unterstützt Muster und vermeidet Wortaufteilung.

4.2 Aktionen mit if, elif, else und case auswählen

Bedingungen werden nützlich, wenn sie Aktionen auswählen. Ein if-Block wählt anhand von Befehlsergebnissen einen Zweig. Ein case-Block wählt einen Zweig, indem er einen Wert mit Mustern abgleicht. Beide machen die verfügbaren Aktionen im Skript sichtbar.

Einen Befehl einen Zweig wählen lassen
if grep -q ERROR app.log; then
  echo "Errors found"
else
  echo "No successful match"
fi

if führt den Befehl aus und betritt den ersten Zweig, wenn er 0 liefert. Andernfalls betritt es else. Die Suche selbst ist die Bedingung; du musst sie nicht ausführen, etwas ausgeben und dann $? prüfen. Auch ein grep-Fehler liefert einen Wert ungleich null. Deshalb beschreibt dieses Beispiel den else-Zweig als Suche ohne erfolgreichen Treffer und nicht als Beweis, dass die Datei keine Fehler enthält.

then muss einen neuen Befehl beginnen: Setze es in die nächste Zeile oder nach ein Semikolon. fi schließt den Block. Ein fehlendes fi erzeugt häufig einen Syntaxfehler am Dateiende, weil Bash noch darauf wartet, dass der Block geschlossen wird.

Überlappende Bedingungen ordnen

elif fügt einen Test hinzu, der nur läuft, wenn frühere Tests fehlgeschlagen sind. Für eine ganzzahlige Prozentangabe der Speicherplatzbelegung:

if [ "$usage" -ge 90 ]; then
  echo "CRITICAL: disk ${usage}% full"
elif [ "$usage" -ge 75 ]; then
  echo "WARNING: disk ${usage}% full"
else
  echo "OK: disk ${usage}% full"
fi

Bei usage=82 schlägt der erste Test fehl und der zweite ist erfolgreich. Die Ausgabe lautet „WARNING: disk 82% full“. Bei 95 läuft der erste Zweig und der Warnungszweig wird übersprungen. Stünde der Test auf 75 zuerst, würde 95 darauf zutreffen und der kritische Test nie erreicht werden. Ordne überlappende Bereiche so an, dass die strengere Bedingung zum Zug kommt.

Nur der erste erfolgreiche Zweig wird ausgeführt. else braucht keine Bedingung und behandelt die übrigen Fälle. elif oder else kann entfallen, wenn die Aufgabe den jeweiligen Teil nicht benötigt.

Einen Wert mit case abgleichen
case "$1" in
  start) echo "Starting" ;;
  stop) echo "Stopping" ;;
  y|Y|yes) echo "Confirmed" ;;
  *) echo "Usage: $0 start|stop|y|Y|yes" >&2; exit 2 ;;
esac

Jedes Muster endet mit ), jeder Zweig mit ;; und esac schließt den Block. Das | innerhalb eines Musters gibt Alternativen an. Das abschließende * ist das Auffangmuster und gehört ans Ende, weil es auf jeden Wert zutrifft.

case verwendet Dateimuster, keine regulären Ausdrücke. *.jpg trifft auf einen Wert zu, der mit .jpg endet. [0-9]* trifft auf einen Wert zu, dessen erstes Zeichen eine Ziffer ist; das * kann dann auf beliebigen folgenden Text passen und trifft daher auch auf „7draft“ zu. Es beweist nicht, dass ein ganzer Wert nur Ziffern enthält.

Die passende Struktur wählen

Verwende case, wenn eine Eingabe wie ein Unterbefehl oder eine Antwort mehrere benannte Formen hat. Verwende if, wenn Bedingungen Verschiedenes prüfen, etwa ob eine Datei existiert und ob eine Anzahl eine Schranke überschreitet. Ein Musterabgleich fragt nach den Zeichen in einem Wert; eine Dateiprüfung fragt nach dem Pfad auf dem Datenträger. Ein Name mit der Endung .log kann auf ein Muster passen, selbst wenn keine solche Datei existiert.

Wichtige Erkenntnisse

  • if wählt anhand des Rückgabestatus eines Befehls einen Zweig; jeder Befehl kann eine Bedingung sein.
  • elif-Tests laufen nur, nachdem frühere Bedingungen fehlgeschlagen sind.
  • Ordne überlappende Schwellenwerte vom strengeren zum allgemeineren.
  • case wählt das erste passende Muster und beendet jeden Zweig mit ;;.
  • Ein Musterabgleich weist nicht nach, dass eine Datei existiert.

4.3 Befehle mit for für Listenelemente und Dateien wiederholen

Eine for-Schleife gibt demselben Befehlsblock bei jedem Durchlauf einen neuen Wert. Die Liste kann wörtlich angegebene Wörter, passende Dateinamen, einen Zahlenbereich oder die Argumente des Skripts enthalten. Bash weist der Schleifenvariable ein Listenelement zu, bevor der Schleifenkörper ausgeführt wird.

Eine feste Liste durchlaufen
for host in web1 web2 db1; do
  echo "Checking $host"
done

Im ersten Durchlauf gilt host=web1, im zweiten host=web2 und im dritten host=db1. Die Schleife gibt drei Zeilen aus. do öffnet den Schleifenkörper und done schließt ihn. Die Variable bleibt nach der Schleife verfügbar und enthält ihren zuletzt zugewiesenen Wert.

Eine Schleife kann auch ein Ergebnis aufsummieren:

total=0
for n in 4 8 15; do
  total=$(( total + n ))
done
echo "$total"

Die gespeicherte Summe ändert sich von 0 auf 4, dann auf 12 und dann auf 27. Initialisiere die Summe vor der Schleife, damit die erste Addition einen definierten Ausgangswert hat.

Passende Dateien durchlaufen
for f in *.log; do
  [ -f "$f" ] || continue
  gzip -- "$f"
done

Bash expandiert das Glob-Muster zu passenden Namen, bevor der Schleifenkörper läuft. Jeder passende Dateiname bleibt ein Listenelement, auch wenn er Leerzeichen enthält. Das Quoting von "$f" innerhalb des Schleifenkörpers hält dieses Element bei der Übergabe an gzip zusammen. Die Prüfung auf reguläre Dateien überspringt hier auch Verzeichnisse, deren Namen auf .log enden.

Mit den standardmäßigen Glob-Einstellungen von Bash bleibt ein *.log ohne Treffer wörtlich erhalten. Eine Schleife ohne Schutzprüfung würde einmal mit den Zeichen *.log laufen und der Befehl würde fehlschlagen. [ -e "$f" ] || continue überspringt nicht existierende Pfade; verwende -f, wenn nur reguläre Dateien gewünscht sind.

Erstelle keine Dateinamenschleife aus $(ls). Dessen Ausgabe ist Text, sodass die Wortaufteilung „my report.txt“ in zwei Listenelemente zerlegen kann. Ein Glob-Muster liefert die Dateinamen bereits mit ihren vollständigen Grenzen.

Aus jedem alten Namen einen neuen bilden
for f in *.jpeg; do
  [ -f "$f" ] || continue
  mv -- "$f" "${f%.jpeg}.jpg"
done

${f%.jpeg} entfernt die Endung .jpeg aus dem Wert. Für „beach day.jpeg“ wird das Ziel zu „beach day.jpg“. Die beiden Argumente in Anführungszeichen halten beide Pfade zusammen. -- teilt mv mit, dass die folgenden Argumente Namen sind, selbst wenn einer mit - beginnt. Verwende beim Ausprobieren des Beispiels ein Zielverzeichnis ohne gleichnamige Dateien, da mv ein existierendes Ziel ersetzen kann.

Einen Bereich durchzählen

for i in {1..5} liefert 1 bis 5. Bash expandiert die geschweiften Klammern vor den Variablen, sodass {1..$n} keinen Bereich variabler Länge erzeugt. Verwende für eine gespeicherte Schranke die arithmetische Form:

for (( i = 1; i <= n; i++ )); do
  echo "$i"
done

Der erste Ausdruck initialisiert den Zähler, der mittlere prüft ihn vor jedem Durchlauf und der letzte aktualisiert ihn. Auch for i in $(seq 1 "$n") erzeugt für eine passende positive ganzzahlige Schranke eine Zahlenliste. Die hier absichtlich ohne Quoting verwendete Substitution liefert separate Zahlen.

Für Argumente liefert for arg in "$@" ein Element pro ursprünglichem Argument. Das kürzere for arg; do bedeutet dasselbe und erhält auch Leerzeichen innerhalb jedes Arguments.

Wichtige Erkenntnisse

  • Eine for-Schleife führt ihren Schleifenkörper einmal pro Listenelement aus.
  • Glob-Muster liefern vollständige Dateinamen; setze die Schleifenvariable im Schleifenkörper in Anführungszeichen.
  • Ein Glob-Muster ohne Treffer bleibt bei den Standardeinstellungen von Bash wörtlich erhalten. Sichere Dateischleifen daher mit einer Prüfung ab.
  • Vermeide Dateinamenschleifen aus $(ls).
  • Bereiche in geschweiften Klammern stehen vor der Variablenexpansion fest; verwende für eine variable Schranke eine arithmetische Schleife.
  • "$@" erhält die ursprünglichen Grenzen der Argumente.

4.4 Befehle mit while und until wiederholen, bis sich eine Bedingung ändert

Manche Wiederholungen enden, wenn sich eine Bedingung ändert, und nicht, wenn eine Liste aufgebraucht ist. while und until prüfen vor jedem Durchlauf. Ein while-Schleifenkörper läuft, solange seine Bedingung erfolgreich ist; ein until-Schleifenkörper läuft, solange seine Bedingung fehlschlägt. Beide Schleifen können auch kein einziges Mal laufen.

Aktualisieren, wovon die Bedingung abhängt
i=1
while [ "$i" -le 3 ]; do
  echo "Attempt $i"
  i=$(( i + 1 ))
done

Die Bedingung erhält zuerst 1, dann 2 und dann 3. Der Schleifenkörper gibt diese drei Versuchsnummern aus und erhöht den Zähler jedes Mal. Nach der Aktualisierung auf 4 schlägt der nächste Test fehl und die Schleife endet. Fehlte die Aktualisierung, bliebe i bei 1 und die Schleife liefe weiter. Strg+C stoppt eine laufende Vordergrundschleife.

Um auf eine Datei zu warten:

until [ -f /tmp/export.done ]; do
  sleep 5
done

Existiert die Datei bereits, läuft der Schleifenkörper kein einziges Mal. Andernfalls pausiert sleep 5 fünf Sekunden vor der nächsten Prüfung. Eine Pause verhindert, dass die Schleife ununterbrochen prüft und Prozessorzeit verschwendet.

Datensätze als Zeilen lesen
while IFS= read -r line; do
  echo "Host: $line"
done < hosts.txt

read liefert bei jedem Durchlauf eine Zeile und gibt am Dateiende einen Fehlerstatus zurück. IFS= erhält Leerzeichen am Anfang und Ende der Zeile; -r erhält Backslashes. Die Eingabeumleitung nach done führt die Datei der gesamten Schleife zu, nicht nur ihrem letzten Befehl.

Eine Zeile wie „web1 production“ bleibt ein Wert. for line in $(cat hosts.txt) würde an Leerzeichen, Tabulatoren und Zeilenvorschüben aufteilen und diese beiden Wörter als separate Schleifendurchläufe behandeln. Diese Form kann beliebige zeilenbasierte Datensätze nicht erhalten.

Änderungen nach der Schleife erhalten

Eine Pipe in eine Schleife wie cat hosts.txt | while read -r line; do ...; done führt die Schleife in Bash normalerweise in einem Kindprozess aus. Ein dort geänderter Zähler geht für den Elternprozess verloren, wenn der Kindprozess endet. Leite die Datei in die Schleife um, wenn spätere Befehle deren aufsummierte Werte benötigen:

count=0
while IFS= read -r line; do
  count=$(( count + 1 ))
done < hosts.txt
echo "$count"

Dies verarbeitet Zeilen mit abschließendem Zeilenvorschub und erhält den aktualisierten Zähler in der aktuellen Shell. Für die Schleife erzeugt keine Pipeline einen Kindprozess.

Den letzten Datensatz und vorzeitige Abbrüche behandeln

Eine Datei kann mit Text, aber ohne abschließenden Zeilenvorschub enden. read speichert diesen letzten Text, meldet aber einen Fehlschlag, sodass ein einfaches while read für diesen Datensatz nicht in den Schleifenkörper eintritt. Ergänze einen zweiten Test, um den gespeicherten nicht leeren Text anzunehmen:

while IFS= read -r line || [ -n "$line" ]; do
  echo "Host: $line"
done < hosts.txt

break verlässt die Schleife sofort. continue überspringt die verbleibenden Befehle des aktuellen Durchlaufs und kehrt dann zur nächsten Bedingungsprüfung zurück. Eine while true-Schleife braucht daher ein break, ein exit oder ein Signal, um zu enden. Sie kann ein Menü steuern, das bei der Eingabe „q“ abbricht. Setze in einer Zählschleife eine Aktualisierung vor jedes continue, das sie sonst überspringen würde, da sich dieser Durchlauf andernfalls endlos wiederholen könnte.

Wichtige Erkenntnisse

  • while wiederholt nach Erfolg; until wiederholt nach einem Fehlschlag.
  • Beide Schleifen prüfen, bevor sie ihren Schleifenkörper betreten.
  • Aktualisiere einen Zähler oder pausiere eine Abfrageschleife, damit sie ohne ununterbrochenes Prüfen Fortschritte macht.
  • IFS= read -r erhält Leerzeichen und Backslashes bei zeilenweiser Eingabe.
  • Leite eine Datei in die Schleife um, damit geänderte Variablen in der aktuellen Shell erhalten bleiben.
  • Ein zusätzlicher Test auf eine nicht leere Zeichenkette erhält einen letzten Datensatz ohne Zeilenvorschub.
  • break verlässt eine Schleife; continue springt zum nächsten Durchlauf.
5

Argumente an Skripte übergeben

Mit Befehlszeilenargumenten kann ein Skript viele Aufgaben erfüllen, ohne seinen Code zu bearbeiten. Du liest einzelne Werte, erhältst eine vollständige Argumentliste und arbeitest vorangestellte Optionen ab. Bevor die Arbeit beginnt, zählst und prüfst du die Eingaben, erklärst einen korrekten Aufruf und legst Standardwerte für optionale Werte fest. Das Ergebnis kann an einer Eingabeaufforderung oder unbeaufsichtigt laufen und liefert bei unbrauchbarer Eingabe klare Meldungen und einen Rückgabestatus.

5.1 Positionsparameter und Argumentanzahl auslesen

Argumente machen aus einem Skript mit festen Eingaben einen wiederverwendbaren Befehl. Bash legt die Wörter nach dem Skriptnamen in Positionsparametern ab. Ihre Grenzen werden von der aufrufenden Shell festgelegt. Daher ist Quoting sowohl beim Aufruf des Skripts als auch bei der Verwendung dieser Werte wichtig.

Die Parameter bestimmen
./backup.sh /home/sam/docs /mnt/usb

Innerhalb des Skripts ist $0 gleich ./backup.sh, $1 gleich /home/sam/docs und $2 gleich /mnt/usb. $# ist 2, die Anzahl der Argumente. Das Skript kann mit cp -r "$1" "$2" das Quellverzeichnis an das Ziel kopieren, ohne einen der beiden Pfade fest im Code vorzugeben.

$0 bezeichnet den Namen, mit dem das Skript gestartet wurde; er wird in $# nicht mitgezählt. Bei ./greet.sh Ana "Lee Kim" ist das erste Argument „Ana“ und das zweite „Lee Kim“. Ohne die Anführungszeichen um den zweiten Namen würde das Skript drei Argumente erhalten.

Ab dem zehnten Argument geschweifte Klammern verwenden

$1 bis $9 bezeichnen die ersten neun Positionsparameter. Der zehnte braucht ${10} und spätere Positionen folgen derselben Form. $10 bedeutet die Expansion von $1, gefolgt vom wörtlichen Zeichen 0. Ist das erste Argument „Ana“, wird $10 zu „Ana0“, selbst wenn ein zehntes Argument existiert.

Ein ausgelassener Parameter wird bei normalen Einstellungen zu leerem Text expandiert. Bei zwei Argumenten fehlt $3; unter set -u verursacht dessen Expansion einen Fehler wegen einer nicht gesetzten Variable. Prüfe die Anzahl, bevor du erforderliche Positionen liest, oder verwende eine Expansion, die einen Standardwert liefert.

Alle Argumentgrenzen erhalten

Angenommen, ein Skript erhält "a b" und c. Vergleiche:

ExpansionWeitergegebene Wörter
"$@"Zwei: „a b“ und „c“.
"$*"Eines: „a b c“, mit dem üblichen Leerzeichen als Trennzeichen.
$@Drei: „a“, „b“ und „c“ bei normaler Aufteilung.

"$@" ist die übliche Wahl für die Argumentweitergabe:

for arg in "$@"; do
  echo "Argument: $arg"
done

Bei diesem Aufruf läuft die Schleife zweimal, einmal pro ursprünglichem Argument. Ohne Argumente läuft sie kein einziges Mal. Das doppelte Quoting von "$@" hat eine besondere Bedeutung: Jeder Positionsparameter bleibt ein separates Wort. Die Anführungszeichen verbinden also nicht die gesamte Liste zu einem Wort.

"$*" verbindet Werte mit dem ersten Zeichen von IFS, gewöhnlich einem Leerzeichen. Das kann für eine einzelne Anzeigezeichenkette nützlich sein, verliert aber die einzelnen Grenzen, die ein späterer Befehl benötigen kann.

Parameter mit shift abarbeiten

shift entfernt den ersten Positionsparameter, verschiebt die späteren nach unten und verringert $#. Beim Sicherungsaufruf wird $1 nach einem Verschieben zu /mnt/usb und die Anzahl zu 1. shift 2 entfernt die ersten beiden Parameter auf einmal.

Damit lässt sich eine Schleife erstellen, die $1 untersucht, verarbeitet und dann vor dem nächsten Durchlauf verschiebt. Prüfe mit [ "$#" -gt 0 ], ob Argumente übrig sind; andernfalls kann das Skript einen fehlenden Wert lesen oder versuchen, über die verfügbaren Argumente hinaus zu verschieben. Das Verschieben ändert $0 nicht und kann die Argumentliste der Eltern-Shell, die das Skript gestartet hat, nicht ändern.

Wichtige Erkenntnisse

  • $0 ist der Aufrufname, während $1 und die folgenden Parameter Argumente enthalten.
  • $# zählt Argumente; durch Quoting geschützte Leerzeichen bleiben innerhalb eines Arguments.
  • Verwende ${10} für das zehnte Argument; $10 ist $1 gefolgt von 0.
  • "$@" erhält Argumente einzeln, während "$*" sie verbindet.
  • shift entfernt die vorderen Parameter und ändert die verbleibenden Positionen.

5.2 Argumente prüfen, Aufrufhinweise anzeigen und Standardwerte festlegen

Ein Skript sollte vor Arbeitsbeginn feststellen, ob seine Eingaben brauchbar sind. Prüfe zuerst die Anzahl der Argumente und dann ihre Bedeutung. Optionale Eingaben können Standardwerte haben; fehlende erforderliche Eingaben brauchen eine klare Diagnosemeldung und einen Rückgabestatus ungleich null.

Den erwarteten Aufruf erklären
if [ "$#" -ne 2 ]; then
  echo "Usage: $0 SOURCE DEST" >&2
  exit 2
fi

Dies prüft die Anzahl vor der Expansion von $1 oder $2 und funktioniert daher auch unter set -u. Der Aufrufhinweis geht an die Standardfehlerausgabe. Großbuchstaben bezeichnen Werte, die der Benutzer angibt, [DEST] würde ein optionales Ziel bedeuten und FILE... bedeutet ein oder mehrere Dateiargumente. Eine Hilfeoption wie -h gibt normalerweise den Aufrufhinweis aus und beendet das Skript mit 0, weil das Anfordern von Hilfe eine erfolgreiche Verwendung ist.

Die Argumentanzahl allein kann nicht zeigen, ob eine Quelle brauchbar ist. [ -d "$1" ] prüft auf ein existierendes Verzeichnis. Eine Prüfung auf reguläre Dateien kann Dateien auswählen, aber auch das Ergebnis der Operation selbst muss geprüft werden: Rechte oder andere Fehler können das Lesen verhindern.

Einen Standardwert verwenden oder einen Wert verlangen
logdir=${1:-/var/log}
src=${1:?Usage: backup.sh SOURCE [DEST]}

Die erste Form verwendet /var/log, wenn der erste Parameter fehlt oder leer ist. Die zweite beendet in beiden Fällen ein nicht interaktives Skript und gibt seine Meldung auf der Standardfehlerausgabe aus. Der Doppelpunkt ist Teil beider Formen. Ein Standardwert wird für diese Expansion verwendet; ${1:-...} fügt der Liste der Positionsparameter kein Argument hinzu.

Einen teilweisen Fehlschlag festhalten

Ein Skript zum Zählen von Dateizeilen kann nach einer fehlerhaften Eingabe fortfahren und dennoch melden, dass die gesamte Aufgabe unvollständig war:

#!/bin/bash
if [ "$#" -eq 0 ]; then
  echo "Usage: $0 FILE..." >&2
  exit 2
fi
status=0
for f in "$@"; do
  if [ -f "$f" ]; then
    if lines=$(wc -l < "$f"); then
      echo "$f: $lines lines"
    else
      echo "$f: could not count lines" >&2
      status=1
    fi
  else
    echo "$f: not a regular file" >&2
    status=1
  fi
done
exit "$status"

Für notes.txt missing.txt gibt das Skript die Zeilenanzahl der lesbaren Datei aus und meldet die fehlende Datei. Anschließend endet es mit 1. Die Zuweisung wird direkt geprüft, sodass ein Lesefehler nicht zu einer erfolgreichen leeren Anzahl wird. Ein späterer Erfolg setzt das gespeicherte Fehlerkennzeichen nie auf 0 zurück.

Einfache Optionen vor Dateinamen verarbeiten
verbose=0
while [ "$#" -gt 0 ]; do
  case "$1" in
    -v) verbose=1; shift ;;
    -h) echo "Usage: $0 [-v] FILE..."; exit 0 ;;
    --) shift; break ;;
    -*) echo "Unknown option: $1" >&2; exit 2 ;;
    *) break ;;
  esac
done

Jede erkannte Option wird mit shift abgearbeitet. Das erste gewöhnliche Argument beendet die Optionsauswertung; -- beendet sie ebenfalls und wird selbst entfernt. Das verbleibende "$@" enthält die Dateinamen, einschließlich eines Namens, der nach -- mit - beginnt. getopts von Bash unterstützt eine umfassendere Auswertung kurzer Optionen.

Ein unbeaufsichtigtes Skript benötigt alle erforderlichen Eingaben aus Argumenten, Standardwerten oder der Konfiguration. read kann auf ein Terminal warten und blockieren oder am Dateiende sofort fehlschlagen. Würde ein fehlendes Argument durch eine Eingabeaufforderung ersetzt, hätte eine geplante Aufgabe keine zuverlässige Möglichkeit fortzufahren.

Wichtige Erkenntnisse

  • Prüfe die Anzahl, bevor du erforderliche Argumente expandierst.
  • Ein Aufrufhinweis nennt erforderliche, optionale und wiederholbare Eingaben.
  • ${1:-value} liefert einen Standardwert; ${1:?message} weist einen fehlenden oder leeren Wert zurück.
  • Prüfe auch nach der Prüfung des Dateityps der Eingabe das Ergebnis der Operation.
  • Erhalte einen übergreifenden Fehlerstatus, wenn du bei mehreren Eingaben fortfährst.
  • Arbeite Optionen mit shift ab und beachte -- als Ende der Optionen.
6

Skripte zeitgesteuert automatisch ausführen

Ein unbeaufsichtigtes Skript braucht einen Zeitplan und eine Möglichkeit, seine Ergebnisse zu untersuchen. Cron beschreibt passende Uhrzeiten in einer Zeile; systemd verbindet einen Dienst mit einem Timer. Du liest beide Formen, stellst die Umgebung bereit, die die Aufgabe benötigt, und hältst ihre Ausgabe verfügbar. Prüfst du die nächste Aktivierung und das letzte Aufgabenergebnis getrennt, kannst du einen aktiven Zeitplan von tatsächlich erfolgreicher Arbeit unterscheiden.

6.1 Aufgaben mit cron zeitlich planen

Cron startet Befehle zu passenden Uhrzeiten. Die Crontab jedes Benutzers speichert dessen Zeitplan und Aufgaben laufen unter dessen Benutzerkonto. Ein geplantes Skript braucht sowohl einen korrekten Zeitausdruck als auch eine Umgebung, die seine Pfade, Eingaben und sein Ausgabeziel bereitstellt.

Die fünf Felder lesen

Verwende crontab -e, um deine Tabelle zu bearbeiten, und crontab -l, um sie anzusehen. crontab -r löscht die gesamte Tabelle ohne Nachfrage; verwende den Editor, um eine einzelne Aufgabe zu entfernen.

Feld in ReihenfolgeWerte
Minute0–59
Stunde0–23
Tag des Monats1–31
Monat1–12
Wochentag0–7; 0 und 7 bedeuten Sonntag
30 2 * * * /home/sam/bin/backup.sh

Dies läuft täglich um 02:30 Uhr. Sternchen akzeptieren jeden Wert in einem Feld. 0 9 * * 1-5 wählt montags bis freitags 09:00 Uhr und 0 0 1 * * Mitternacht am ersten Tag jedes Monats. Zeiten verwenden die Zeitzone des Systems, sofern die cron-Konfiguration keine andere unterstützte Zeitzone festlegt.

Bereiche, Listen und Schrittweiten kombinieren

Ein Komma listet Werte auf: 1,15 im Feld für den Monatstag wählt den ersten und den fünfzehnten Tag. Ein Bindestrich gibt einen Bereich an und / leitet eine Schrittweite ein. */15 im Minutenfeld wählt 0, 15, 30 und 45.

*/20 8-10 * * * wählt drei Minuten in jeder von drei Stunden: neun tägliche Läufe, beginnend um 08:00 Uhr und endend um 10:40 Uhr. Schrittweiten beginnen innerhalb ihres Feldes neu. */45 läuft zu Minute 0 und Minute 45 jeder Stunde; der Abstand bis zur Minute 0 der folgenden Stunde beträgt nur 15 Minuten.

Sind sowohl der Monatstag als auch der Wochentag eingeschränkt, reicht eine Übereinstimmung in einem der beiden Felder. 0 12 13 * 5 wählt mittags am 13. und an Freitagen, nicht nur an einem Freitag, dem 13. Die anderen Felder müssen weiterhin zutreffen.

Spezielle Zeichenfolgen ersetzen alle fünf Felder: @hourly, @daily, @weekly, @monthly, @yearly und @reboot. @daily bedeutet Mitternacht, während @reboot einmal beim Start läuft.

Pfade bereitstellen und die Ausgabe erhalten

Cron verwendet normalerweise /bin/sh für seine Befehlszeile, einen kurzen PATH und keine Startdatei-Einstellungen einer interaktiven Shell. Der Bash-Shebang eines ausführbaren Skripts wählt weiterhin Bash. Verwende absolute Pfade für das Skript und seine Dateien oder setze PATH am Anfang der Crontab.

30 2 * * * /home/sam/bin/backup.sh >> /home/sam/backup.log 2>&1

Die Aufgabe hängt beide Ausgabeströme an das Protokoll an. Ohne Umleitung versendet cron die Ausgabe per E-Mail, wenn der Mailversand konfiguriert ist, auch über MAILTO; andernfalls kann die Ausgabe verloren gehen. Ein Prozentzeichen hat in einem Crontab-Befehl eine besondere Funktion: Es beginnt eine neue Zeile und die nachfolgende Eingabe. Maskiere dort ein Datumsformat wie in date +\%F. Ein Datumsbefehl innerhalb eines separaten Skripts verwendet das gewöhnliche %F.

Systemzeitpläne und nachgeholte Aufgaben unterscheiden

/etc/crontab und Dateien in /etc/cron.d/ ergänzen nach den fünf Zeitfeldern ein Benutzerfeld. Zum Beispiel läuft 30 2 * * * root /usr/local/bin/backup.sh als root. Füge dieses Benutzerfeld nicht zu einer persönlichen Crontab hinzu.

Viele Distributionen führen auch geeignete ausführbare Dateien in /etc/cron.daily/, /etc/cron.weekly/ und /etc/cron.monthly/ aus. Die Standardregeln für Namen von Debians run-parts überspringen Namen mit Punkten. Verwende dort daher backup-notes und nicht backup-notes.sh. Cron verpasst Zeiten, die bei ausgeschaltetem Computer verstreichen. Anacron kann regelmäßige tägliche, wöchentliche oder monatliche Aufgaben nach dem Start nachholen.

Wichtige Erkenntnisse

  • Eine persönliche Crontab hat fünf Zeitfelder, direkt gefolgt von einem Befehl.
  • Listen, Bereiche und Schrittweiten wählen Werte innerhalb jedes Feldes aus.
  • Sind Monatstag und Wochentag eingeschränkt, reicht eine Übereinstimmung in einem der beiden Felder.
  • Verwende absolute Pfade und ein Ausgabeprotokoll für unbeaufsichtigte Aufgaben.
  • Maskiere % in einem Crontab-Befehl, auch in Datumsformaten.
  • System-Crontabs ergänzen ein Benutzerfeld; auch für Dateien in periodischen Verzeichnissen gelten Zulassungsregeln.
  • Cron verpasst Läufe bei ausgeschaltetem Rechner; anacron unterstützt das Nachholen regelmäßiger Aufgaben.

6.2 Aufgaben mit systemd-Timern zeitlich planen

Systemd trennt die Arbeit von ihrem Zeitplan. Eine Service-Unit beschreibt den auszuführenden Befehl. Eine Timer-Unit beschreibt, wann er gestartet wird. Standardmäßig aktiviert backup.timer die Unit backup.service und verbindet das Paar über den gemeinsamen Grundnamen.

Den Dienst und den kalenderbasierten Zeitplan schreiben

Lege diese System-Units in /etc/systemd/system/ ab:

# backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Type=oneshot eignet sich für ein Skript, das einmal läuft und endet. Verwende einen absoluten Befehlspfad und mache das Skript mit einem Bash-Shebang ausführbar. Der Timer liefert den Zeitplan:

# backup.timer
[Unit]
Description=Run backup.service daily at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

OnCalendar gleicht Datumsangaben und Uhrzeiten ab. Hier akzeptiert das Datum mit Platzhaltern jeden Tag. Persistent=true ermöglicht das Nachholen, nachdem der Timer inaktiv war: Wurde mindestens ein kalenderbasierter Lauf verpasst, startet der Timer den Dienst bei erneuter Aktivierung einmal. Er führt nicht jeden verpassten Lauf erneut aus.

Den Timer laden und aktivieren
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

Lade nach dem Anlegen oder Ändern von Unit-Dateien neu. enable --now startet den Timer sofort und aktiviert ihn für künftige Systemstarts. Die alleinige Aktivierung des Dienstes erstellt keinen Zeitplan. Teste die Arbeit separat mit sudo systemctl start backup.service.

Zwischen Uhrzeit und verstrichener Zeit wählen
EinstellungZeitplan
OnCalendar=Mon..Fri *-*-* 09:00:00Montags bis freitags um 09:00 Uhr
OnCalendar=*:0/15Die Minuten 0, 15, 30 und 45 jeder Stunde
OnBootSec=10minZehn Minuten nach dem Systemstart
OnUnitActiveSec=1hEine Stunde nach der letzten Aktivierung des Dienstes

Kalenderausdrücke können daily für Mitternacht an jedem Tag oder weekly für Montag um Mitternacht verwenden. Prüfe einen Ausdruck mit systemd-analyze calendar "Mon..Fri 09:00", um seine Interpretation und den nächsten Termin zu sehen.

Die letzten beiden Einstellungen sind monotone Timer: Sie messen die seit einem Ereignis verstrichene Zeit. Kombiniere sie für einen ersten Lauf nach dem Systemstart und spätere stündliche Aktivierungen. Persistent=true gilt für kalenderbasierte Timer; es ergänzt kein kalenderbasiertes Nachholen für monotone Timer.

Zeitplanung und Ergebnisse getrennt untersuchen

systemctl list-timers zeigt die nächsten und letzten Aktivierungen. systemctl status backup.service zeigt das Ergebnis des Dienstes und journalctl -u backup.service dessen Ausgabe und Fehler. Ein aufgelisteter nächster Lauf zeigt, dass ein Zeitplan aktiv ist, aber nicht, dass die vorherige Aufgabe des Skripts erfolgreich war.

Timer haben ein Auslösefenster. AccuracySec beträgt standardmäßig eine Minute; AccuracySec=1s verkleinert das Zeitfenster für die Zusammenfassung von Auslösungen. RandomizedDelaySec fügt absichtlich eine zufällige Verzögerung hinzu, um Arbeit auf mehrere Rechner zu verteilen. Diese Einstellungen garantieren unter Last keine exakte Startsekunde.

Einen eigenen Benutzer-Timer ausführen

Benutzer-Unit-Dateien liegen in ~/.config/systemd/user/ und Befehle verwenden systemctl --user, auch daemon-reload, enable --now und list-timers. Ein Benutzermanager läuft normalerweise mit der Sitzung dieses Benutzers. Ein Administrator kann Lingering mit loginctl enable-linger username aktivieren, um ihn auch ohne Anmeldung verfügbar zu halten.

Cron benötigt eine kompakte Zeitzeile und funktioniert ohne systemd. Timer ergänzen ein Dienstergebnis und ein Journal, das Nachholen kalenderbasierter Aufgaben und mehr Kontrolle. Normalerweise lädt keines von beiden ~/.bashrc; beide benötigen Skripte, die mit ausdrücklichen Pfaden und ohne interaktive Eingabeaufforderungen funktionieren.

Wichtige Erkenntnisse

  • Der Dienst legt fest, was ausgeführt wird; der Timer legt fest, wann.
  • Lade geänderte Units neu und aktiviere den .timer mit --now.
  • Kalenderbasierte Timer folgen der Uhrzeit; monotone Timer messen ab Ereignissen.
  • Persistent=true holt verpasste kalenderbasierte Arbeit bei erneuter Aktivierung einmal nach.
  • Prüfe sowohl die nächste Aktivierung des Timers als auch Status und Journal des Dienstes.
  • Benutzer-Timer brauchen einen laufenden Benutzermanager und für Läufe ohne Sitzung Lingering.

Shellskripterstellung: Beispiele

6 Interaktive Lektionen

1

Einen wiederholbaren Verzeichnisbericht speichern

9 Schritte
Erstelle einen kleinen Bash-Bericht, führe ihn über einen Pfad aus und unterscheide Ausführung von Sourcing.
  1. 1
    EinführungEine wiederkehrende Aufgabe an einer Stelle ablegen

    Du prüfst häufig, wo du dich befindest, listest ein Verzeichnis auf und gibst eine Abschlussmeldung aus. Wenn du die Befehle speicherst, lässt sich ihre Reihenfolge wiederholen.

    Ein Skript ist eine reine Textdatei, die von einem Interpreter gelesen wird. Du erstellst einen kleinen Bericht, wählst ausdrücklich Bash und führst ihn in einer Kind-Shell aus. Der Name der Datei, ihr Ausführungsrecht und ihr Speicherort beantworten jeweils eine andere Frage zu ihrem Start.

  2. 2
    BeispielDie Befehle der Reihe nach schreiben

    Speichere dies in einem Editor für reinen Text als folder-report.sh:

    #!/bin/bash
    pwd
    ls
    echo "Report finished"
    

    Der Shebang wählt Bash, wenn die Datei direkt ausgeführt wird. Der Kommentar erklärt die Aufgabe, wird aber nicht ausgeführt. Bash führt dann pwd, ls und echo in dieser Reihenfolge aus. Die Endung .sh hilft beim Erkennen der Datei; sie wählt den Interpreter nicht aus.

  3. 3
    HerausforderungPrüfen, was die Sprache auswählt

    Ein Kollege ändert die erste Zeile in #!/bin/sh und fügt später [[ ... ]] hinzu. Die Datei endet weiterhin auf .sh. Warum kann sie fehlschlagen?

    ---reveal---

    Der Shebang wählt sh, was dash sein kann und [[ ... ]] von Bash möglicherweise nicht versteht. Die Dateiendung wählt die Sprache nicht aus. Stelle für Bash-Funktionen einen Bash-Shebang wieder her, mit #! ganz am Anfang der ersten Zeile.

  4. 4
    ErklärungDie Datei zuerst mit Bash lesen

    Führe bash folder-report.sh aus. Dies startet Bash und übergibt ihr die lesbare Skriptdatei; Ausführungsrecht für das Skript ist nicht nötig. Der gewählte Interpreter ist bereits Bash, sodass der Shebang diese Wahl nicht trifft.

    Du solltest einen Pfad, eine Auflistung und die Meldung „Report finished“ sehen. Relative Pfade, die Befehle innerhalb des Skripts verwenden, werden von seinem Arbeitsverzeichnis aus aufgelöst, nicht automatisch vom Verzeichnis der Skriptdatei.

  5. 5
    BeispielDie direkte Ausführung erlauben

    Füge für den Eigentümer Ausführungsrecht hinzu und führe den genauen Pfad aus:

    chmod u+x folder-report.sh
    ./folder-report.sh
    

    ./ bezeichnet das aktuelle Verzeichnis. Die direkte Ausführung verwendet den Shebang der Datei. Ist die Datei lesbar, aber nicht ausführbar, kann der frühere bash-Befehl funktionieren, während dieser Befehl mit „Permission denied“ fehlschlägt. Berechtigung und Interpreterauswahl sind separate Teile des Starts.

  6. 6
    TippDas Skript über seinen Namen finden

    Gibst du folder-report.sh ohne Schrägstrich ein, sucht Bash im PATH. Das aktuelle Verzeichnis steht normalerweise nicht auf dieser Liste.

    Mit einem persönlichen bin-Verzeichnis kannst du das Skript aus anderen Verzeichnissen ausführen, wenn es auf dem PATH steht. Sieh dir echo "$PATH" an und verwende command -v folder-report.sh, um zu sehen, welche ausführbare Datei dieser Name auswählt. Steht eine alte Kopie zuerst auf dem PATH, ändert die Bearbeitung einer neueren Kopie an anderer Stelle nicht, was dieser Name ausführt.

  7. 7
    HerausforderungEinen Verzeichniswechsel in der richtigen Shell erhalten

    Das Skript beginnt nun mit cd /var/log. Befindet sich dein Terminal nach dem Ende von ./folder-report.sh dort? Wie könnte eine Einstellungsdatei es dorthin bewegen?

    ---reveal---

    Das ausgeführte Skript läuft in einer Kind-Shell, sodass sein Verzeichniswechsel das übergeordnete Terminal nicht verschiebt. Das Einlesen einer Datei mit source ./settings.sh führt ihre Befehle in der aktuellen Shell aus und kann das Verzeichnis dieser Sitzung ändern. Sourcing verwendet die Sprache der aktuellen Shell.

  8. 8
    HerausforderungDen Start vor dem Bearbeiten der Befehle untersuchen

    Ein lesbarer Bericht funktioniert mit bash folder-report.sh. Die direkte Ausführung meldet „Permission denied“ und die alleinige Eingabe seines Namens meldet „command not found“. Welche zwei Startprobleme solltest du prüfen?

    ---reveal---

    Prüfe das Ausführungsrecht des Skripts für die direkte Ausführung. Prüfe dann PATH oder verwende zur Suche seinen ausdrücklichen ./-Pfad. Ein gültiger Bash-Shebang wählt den Interpreter, kann aber weder Rechte erteilen noch die Datei auf den PATH setzen.

  9. 9
    ZusammenfassungEin Start umfasst mehrere getrennte Entscheidungen

    Die Datei enthält die Befehlsfolge. Der Interpreter liest ihre Sprache, Rechte erlauben die direkte Ausführung und PATH oder ein Schrägstrich findet die Datei.

    Ein ausgeführtes Skript arbeitet in einer Kind-Shell. Eine mit source eingelesene Einstellungsdatei arbeitet in der bereits geöffneten Shell, sodass ihre Zuweisungen und Verzeichniswechsel in dieser Sitzung erhalten bleiben können.

2

Einen Berichtsnamen mit Datum bilden, ohne Leerzeichen zu verlieren

11 Schritte
Verfolge Werte durch Zuweisung, Quoting, Befehlserfassung und Ganzzahlberechnungen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungEinen Wert in einen Befehl verfolgen
  2. 2
    BeispielEin mehrteiliges Ziel speichern
  3. 3
    VerbindungDie Einstellung an einen Kindprozess übergeben
  4. 4
    HerausforderungEinen Namen von seinem Suffix trennen
  5. 5
    BeispielDen gespeicherten Pfad erhalten
  6. 6
    HerausforderungFesten oder veränderlichen Text wählen
  7. 7
    BeispielEin Datum für den Namen erfassen
  8. 8
    BeispielVor dem Einsetzen des Werts rechnen
  9. 9
    HerausforderungDen verlorenen Bruchteil finden
  10. 10
    HerausforderungDen Pfad und den erfassten Wert verbinden
  11. 11
    ZusammenfassungDie drei Aufgaben unterscheiden
3

Verhindern, dass eine fehlgeschlagene Suche zu einem erfolgreichen Bericht wird

10 Schritte
Untersuche eine Pipeline, erhalte einen Fehlschlag und wähle die richtige Prüfung zur Fehlersuche.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungDas Ergebnis als Teil der Aufgabe behandeln
  2. 2
    BeispielDen versteckten Fehler eines früheren Befehls erkennen
  3. 3
    KernaussageDie Pipeline ihren Fehlschlag melden lassen
  4. 4
    HerausforderungDen wichtigen Status speichern
  5. 5
    BeispielDie fehlgeschlagene Arbeit ausdrücklich behandeln
  6. 6
    ErklärungSyntaxprüfung oder Ablaufverfolgung wählen
  7. 7
    ErklärungDie Fehleroptionen als getrennte Einstellungen lesen
  8. 8
    HerausforderungErklären, warum dieses Skript weiterläuft
  9. 9
    HerausforderungDen Aufrufer informiert halten
  10. 10
    ZusammenfassungSowohl die Daten als auch das Ergebnis lesen
4

Eingehende Dateien untersuchen und ihre Datensätze lesen

15 Schritte
Verwende Tests, geordnete Zweige und Schleifen, um Dateien zu verarbeiten, ohne Namen oder Zeilen zu verlieren.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungFür jede Art von Eingabe den nächsten Schritt wählen
  2. 2
    BeispielEinen Test für den Typ des Pfads wählen
  3. 3
    ErklärungWerte richtig vergleichen
  4. 4
    HerausforderungEine negierte Dateiprüfung deuten
  5. 5
    BeispielEine Aktion anhand eines Befehlsergebnisses auswählen
  6. 6
    HerausforderungÜberlappende Schwellenwerte verfolgen
  7. 7
    ErklärungEin Aktionswort mit case abgleichen
  8. 8
    BeispielEine Datei pro Durchlauf an eine Glob-Schleife übergeben
  9. 9
    HerausforderungDen Fall eines leeren Verzeichnisses erklären
  10. 10
    TippEine variable Zahlenschranke wählen
  11. 11
    BeispielEinen Datensatz lesen, ohne ihn an Leerzeichen aufzuteilen
  12. 12
    HerausforderungDen letzten Datensatz ohne Zeilenvorschub erhalten
  13. 13
    VerbindungWarten, ohne ununterbrochen zu prüfen
  14. 14
    HerausforderungEine Summe untersuchen, die null bleibt
  15. 15
    ZusammenfassungDie Struktur an die Daten anpassen
5

Dateieingaben annehmen und teilweisen Fehlschlag melden

10 Schritte
Prüfe einen wiederverwendbaren Befehl, arbeite eine Option ab und erhalte das Gesamtergebnis.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungDie Eingabe zum Teil des Befehlsaufrufs machen
  2. 2
    BeispielDie Grenzen beim Aufruf untersuchen
  3. 3
    ErklärungDie vorangestellte Option abarbeiten
  4. 4
    HerausforderungEin leeres Argument mitzählen
  5. 5
    BeispielEinen Aufruf ohne Dateieingaben zurückweisen
  6. 6
    ErklärungNur für optionale Eingaben einen Standardwert wählen
  7. 7
    BeispielDen Lesevorgang selbst prüfen
  8. 8
    HerausforderungDen früheren Fehlschlag festhalten
  9. 9
    HerausforderungDie Auswertung vor einem Dateinamen mit Bindestrich stoppen
  10. 10
    ZusammenfassungWiederverwendbaren Befehlen ein verlässliches Verhalten geben
6

Einen Bericht zeitlich planen und seinen letzten Lauf prüfen

12 Schritte
Lies cron-Ausdrücke, erstelle ein Timer-Paar und unterscheide geplante Zeit von erfolgreicher Ausführung.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungNur Arbeit mit vollständigen Eingaben zeitlich planen
  2. 2
    BeispielEinen persönlichen Crontab-Eintrag lesen
  3. 3
    HerausforderungEine Minutenschrittweite über eine Stundengrenze verfolgen
  4. 4
    TippDer Aufgabe ein Ausgabeziel geben
  5. 5
    VerbindungEinen verpassten von einem fehlgeschlagenen Lauf unterscheiden
  6. 6
    BeispielDie Arbeit in einem Dienst festlegen
  7. 7
    BeispielDie Zeit im passenden Timer festlegen
  8. 8
    ErklärungÄnderungen laden und den Zeitplan aktivieren
  9. 9
    HerausforderungDas Ergebnis ebenso wie den nächsten Zeitpunkt prüfen
  10. 10
    ErklärungBei Bedarf Zeit ab einem Ereignis zählen
  11. 11
    HerausforderungDas Nachholen nach einer Ausfallzeit wählen
  12. 12
    ZusammenfassungZeitplan und Aufgabe getrennt untersuchen

Shellskripterstellung: Übungsaufgaben

50 Übungsfragen in 5 Sets

Set 1: Kleine Bash-Skripte lesen und ausführen10 Übungsfragen

Frage 1 von 10

Ein Skript verwendet die Bash-Syntax [[ ... ]], aber seine erste Zeile ist #!/bin/sh. Auf diesem Rechner ist sh die Shell dash. Welche erste Zeile wählt den beabsichtigten Interpreter?
  1. #!/bin/sh bash
  2. # /bin/bash
  3. #!/bin/bash
  4. #!/usr/bin/env sh
Antwort zeigenAntwort ausblenden
Antwort: C
#!/bin/bash weist Linux an, bei der Ausführung der Datei Bash zu verwenden. Der aktuelle Shebang wählt dash, das [[ ... ]] nicht unterstützt. Das Ergänzen des Wortes „bash“ nach /bin/sh würde weiterhin sh starten.

Frage 2 von 10

Ein Skript ist für seinen Eigentümer lesbar, hat aber kein Ausführungsrecht. Wie kann der Eigentümer seine Bash-Befehle ausführen, ohne dieses Recht zu ändern?
  1. ./audit.sh
  2. bash audit.sh
  3. chmod u-x audit.sh
  4. source bash audit.sh
Antwort zeigenAntwort ausblenden
Antwort: B
bash audit.sh startet den Interpreter und lässt ihn die Datei lesen, sodass Ausführungsrecht für das Skript nicht nötig ist. ./audit.sh versucht, die Datei direkt auszuführen, und braucht daher dieses Recht. Das Einlesen einer Datei mit source würde ihre Befehle in der aktuellen Shell ausführen, aber source bash audit.sh nennt die falsche Datei.

Frage 3 von 10

Welche Argumente formatiert printf '<%s>\n' "$label" bei label="west side"?
  1. Ein Argument: west side.
  2. Zwei Argumente: west und side.
  3. Ein Argument: das wörtliche $label.
  4. Ein Argument: das wörtliche "west side".
Antwort zeigenAntwort ausblenden
Antwort: A
Die Expansion in doppelten Anführungszeichen liefert den gespeicherten Wert einschließlich des enthaltenen Leerzeichens als ein Argument. Die Shell entfernt die gruppierenden Anführungszeichen, bevor printf den Wert erhält. Eine Expansion ohne Quoting ergäbe zwei Wörter; einfache Anführungszeichen um die Expansion ergäben das wörtliche $label.

Frage 4 von 10

Ein Skript setzt file="shift notes.txt". Wie sollte es diese eine Datei in das existierende Verzeichnis saved kopieren?
  1. cp '$file' saved/
  2. cp $file saved/
  3. cp "file" saved/
  4. cp "$file" saved/
Antwort zeigenAntwort ausblenden
Antwort: D
Doppelte Anführungszeichen erlauben die Expansion der Variable und halten das Leerzeichen innerhalb eines Pfadarguments. $file ohne Quoting wird in „shift“ und „notes.txt“ aufgeteilt, sodass cp zwei Quellnamen erhält. Einfache Anführungszeichen erhalten die Zeichen $file wörtlich und setzen den gespeicherten Pfad nicht ein.

Frage 5 von 10

Ein Befehl ist gerade mit Status 7 fehlgeschlagen. Welche Zuweisung erhält dieses Ergebnis sofort für die spätere Verwendung?
  1. result=$#
  2. result=$?
  3. result=$!
  4. result=0
Antwort zeigenAntwort ausblenden
Antwort: B
$? enthält den Rückgabestatus des letzten Befehls, sodass die sofortige Zuweisung 7 speichert. $# zählt dagegen Positionsargumente und kann den fehlgeschlagenen Befehl nicht beschreiben. Führe vor dem Speichern des Ergebnisses keinen weiteren Befehl aus, da dieser den Status ersetzen würde, den du erhalten möchtest.

Frage 6 von 10

Der Pfad archive existiert und ist ein Verzeichnis. Was sind die Ergebnisse von [ -f archive ] und [ -d archive ] in dieser Reihenfolge?
  1. Wahr, dann wahr.
  2. Wahr, dann falsch.
  3. Falsch, dann wahr.
  4. Falsch, dann falsch.
Antwort zeigenAntwort ausblenden
Antwort: C
-f verlangt eine existierende reguläre Datei, während -d ein existierendes Verzeichnis verlangt. Das Verzeichnis besteht daher den ersten Test nicht, aber den zweiten. Die bloße Existenz macht nicht beide wahr: -e würde die allgemeine Existenz prüfen, ohne einen dieser bestimmten Typen zu verlangen.

Frage 7 von 10

Was gibt dieser Code aus?

used=14
limit=20
percent=$(( used * 100 / limit ))
if [ "$percent" -ge 60 ]; then
  used=$(( used + 2 ))
elif [ "$percent" -ge 70 ]; then
  used=$(( used + 5 ))
fi
echo "$used"
  1. 16
  2. 19
  3. 21
  4. 14
Antwort zeigenAntwort ausblenden
Antwort: A
Der berechnete Prozentsatz ist 70, sodass die erste Bedingung erfüllt ist und 2 zu used addiert werden. Das ergibt 16. Bash überspringt dann den elif-Zweig, obwohl auch dessen Schwellenwert zuträfe. Wer 5 addiert oder beide Aktualisierungen anwendet, übersieht, dass eine if-Kette nur den ersten erfolgreichen Zweig auswählt.

Frage 8 von 10

Ein Skript wird mit ./label.sh "East Wing" report.txt aufgerufen. Welche Werte haben $# und $2?
  1. 3 und Wing.
  2. 2 und East Wing.
  3. 3 und report.txt.
  4. 2 und report.txt.
Antwort zeigenAntwort ausblenden
Antwort: D
Die Wörter „East Wing“ in Anführungszeichen bilden ein Argument und report.txt ist das zweite. $# ist daher 2 und $2 ist report.txt. Der Skriptname gehört zu $0 und wird nicht mitgezählt; würden die beiden Wörter innerhalb des Namens in Anführungszeichen gezählt, ergäben sich fälschlich drei Argumente.

Frage 9 von 10

Ein nicht interaktives Bash-Skript verwendet dir=${1:-/srv/logs}. Es wird mit einem Argument aufgerufen, das eine leere Zeichenkette in Anführungszeichen ist. Welcher Wert wird zugewiesen?
  1. Eine leere Zeichenkette.
  2. Der wörtliche Text ${1}.
  3. /srv/logs
  4. Das Skript endet mit einem Fehler.
Antwort zeigenAntwort ausblenden
Antwort: C
Die :--Expansion wählt den Standardwert, wenn der Parameter nicht gesetzt oder leer ist. Daher verwendet ein ausdrücklich leeres erstes Argument /srv/logs. Das Argument existiert weiterhin in der Positionsliste, aber sein leerer Wert erfüllt die Bedingung für den Standardwert. Die Form :? würde bei dieser Eingabe stattdessen einen Fehler melden.

Frage 10 von 10

Welchen Zeitplan legt 25 4 * * * /home/rae/bin/audit.sh in einer persönlichen Crontab fest?
  1. Jeden Tag um 04:25 Uhr.
  2. Jeden Tag um 25:04 Uhr.
  3. Jede Stunde zur Minute 4.
  4. Am 4. Tag um 00:25 Uhr.
Antwort zeigenAntwort ausblenden
Antwort: A
Das erste Feld ist die Minute 25 und das zweite die Stunde 4. Die übrigen Sternchen erlauben jeden Tag, Monat und Wochentag, sodass täglich um 04:25 Uhr ein Lauf stattfindet. Ein Vertauschen von Minute und Stunde würde die ungültige Stunde 25 erfordern; der Tag des Monats steht im dritten Feld, nicht im zweiten.
Set 2: Werte, Datensätze und Zeitpläne verfolgen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Ein direkt ausgeführtes Skript meldet /bin/bash^M: bad interpreter, aber /bin/bash existiert. Welche Dateiänderung behebt das angezeigte Problem?
  1. Die Skriptendung von .sh in .bash ändern.
  2. Das Skript in ein Verzeichnis auf dem PATH verschieben.
  3. Dem Eigentümer Ausführungsrecht für das Skript geben.
  4. Das Skript in Unix-Zeilenenden umwandeln.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Wie weist du den Text „North Hall“ einer Bash-Variable namens site zu?
  1. site="North Hall"
  2. site = "North Hall"
  3. $site="North Hall"
  4. site=North Hall
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Welchen Wert weist left=$(( 29 % 6 )) zu?
  1. 4
  2. 4.83
  3. 5
  4. 1
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

In einem Skript fehlt ein abschließendes done. Welcher Befehl kann dieses Syntaxproblem erkennen, ohne das Skript auszuführen?
  1. bash -x batch.sh
  2. bash -n batch.sh
  3. bash batch.sh
  4. source ./batch.sh
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Was sind die Ergebnisse von [ 06 = 6 ] und [ 06 -eq 6 ] in dieser Reihenfolge?
  1. Wahr, dann falsch.
  2. Wahr, dann wahr.
  3. Falsch, dann wahr.
  4. Falsch, dann falsch.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Verzeichnis enthält a.csv und late batch.csv, beides reguläre Dateien. Welche Werte werden in for f in *.csv; do echo "$f"; done verwendet?
  1. Zwei Elemente: a.csv und late batch.csv.
  2. Drei Elemente: a.csv, late und batch.csv.
  3. Ein Element: das wörtliche Muster *.csv.
  4. Ein Element: a.csv late batch.csv.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Datei enthält oak, einen Zeilenvorschub und dann elm ohne abschließenden Zeilenvorschub. Welche Anzahl wird ausgegeben?

count=0
while IFS= read -r line; do
  count=$(( count + 1 ))
done < trees.txt
echo "$count"
  1. 0
  2. 2
  3. 3
  4. 1
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Nach dem Aufruf ./task.sh -v "blue room" output.txt führt das Skript shift aus. Welche Werte haben $1 und $# jetzt?
  1. -v und 2.
  2. blue room und 2.
  3. blue und 3.
  4. output.txt und 1.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Wie oft pro Tag läuft */25 10-12 * * * und wann findet der letzte Lauf statt?
  1. 6-mal; zuletzt um 12:25 Uhr.
  2. 8-mal; zuletzt um 12:55 Uhr.
  3. 9-mal; zuletzt um 12:50 Uhr.
  4. 9-mal; zuletzt um 13:00 Uhr.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Welchen Dienst aktiviert inventory.timer bei der standardmäßigen Zuordnung von Units?
  1. inventory.service
  2. timer.service
  3. inventory.timer.service
  4. inventory.target
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Daten durch ein vollständiges Skript verfolgen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine Bash im Terminal beginnt mit zone=west. Die Datei settings.sh enthält nur zone=east. Das Terminal führt erst bash settings.sh, dann source ./settings.sh und dann bash -c 'echo "${zone:-unset}"' aus. Die Variable wurde nie exportiert. Was gibt der letzte Befehl aus?
  1. east
  2. unset
  3. west
  4. Eine leere Zeile.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was gibt echo "${name}_ready" bei name=archive aus?
  1. name_ready
  2. archive
  3. Eine leere Zeile.
  4. archive_ready
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein Skript speichert completed=18 und total=32. Welches ganzzahlige Ergebnis liefert $(( completed * 100 / total ))?
  1. 56
  2. 0
  3. 57
  4. 56.25
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Die Datei absent.log existiert nicht. Welcher Rückgabestatus erreicht den Aufrufer?

#!/bin/bash
set -o pipefail
grep NOTICE absent.log | wc -l
status=$?
echo "Count ended"
exit "$status"
  1. 0
  2. 1
  3. 2
  4. 127
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Was gibt dieses Skript aus?

set -e
false || echo "Handled"
echo "Next"
  1. Nur Handled.
  2. Nur Next.
  3. Handled, dann Next.
  4. Es wird nichts ausgegeben.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Warum sollte *) in einem case-Block auf die benannten Aktionsmuster folgen?
  1. Es trifft auf jeden Wert zu und würde spätere Zweige verdecken.
  2. Es trifft auf keinen Wert zu, bevor ein benanntes Muster fehlschlägt.
  3. Es wiederholt den vorherigen Zweig für Werte ohne Treffer.
  4. Es gilt nur für Dateinamen im aktuellen Verzeichnis.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Das aktuelle Verzeichnis enthält nur die regulären Dateien draft one.jpeg, final.jpeg und notes.txt. Was wird ausgegeben?

count=0
for f in *.jpeg; do
  [ "$f" = final.jpeg ] && continue
  echo "${f%.jpeg}.jpg"
  count=$(( count + 1 ))
done
echo "$count"
  1. draft.jpg, dann one.jpg, dann 2.
  2. draft one.jpg, dann final.jpg, dann 2.
  3. draft one.jpeg.jpg, dann 1.
  4. draft one.jpg, dann 1.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Skript führt until [ -f /tmp/upload.ready ]; do sleep 3; done aus. Die reguläre Datei existiert bereits, bevor die Schleife beginnt. Wie oft läuft der Schleifenkörper?
  1. Genau einmal.
  2. Kein einziges Mal.
  3. Ohne Ende.
  4. Bis zur Entfernung.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein Stapelskript beginnt mit status=0. Eine fehlerhafte Eingabe setzt status=1 und eine spätere Eingabe wird erfolgreich verarbeitet. Welcher Abschluss meldet, dass der Auftrag unvollständig war?
  1. Nach Erfolg status=0 setzen und exit "$status" verwenden.
  2. status=1 erhalten und mit einem erfolgreichen echo enden.
  3. status=0 setzen und einen Fehler auf die Standardausgabe schreiben.
  4. status=1 erhalten und exit "$status" verwenden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Neue Dateien für einen System-Timer und einen Dienst wurden geschrieben. Welcher Befehl lässt systemd ihre Definitionen erneut einlesen, bevor der Timer aktiviert wird?
  1. sudo systemctl daemon-reload
  2. sudo systemctl start report.service
  3. sudo systemctl list-timers
  4. sudo journalctl -u report.service
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Eingaben, Kontrollfluss und Ausfallzeiten untersuchen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine Skriptdatei wird von weekly.sh in weekly umbenannt, wobei Inhalt und Rechte unverändert bleiben. Wie wirkt sich der Verlust der Endung auf die Interpreterauswahl von Linux anhand des Shebangs aus?
  1. Linux wählt dadurch die aktuelle Login-Shell.
  2. Linux wählt dadurch standardmäßig /bin/sh.
  3. Die Interpreterauswahl bleibt unverändert.
  4. Linux kann dadurch den Shebang nicht lesen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine Bash im Elternprozess führt export REGION=north aus und startet dann ein Skript, das REGION=south zuweist und endet. Welcher Wert bleibt im Elternprozess erhalten?
  1. north
  2. south
  3. Ein leerer Wert.
  4. Die Variable wird entfernt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

In einem ansonsten leeren Verzeichnis setzt ein Skript pattern="*.txt". Welches Argument erhält touch "$pattern"?
  1. Keinen Pfad, weil nichts passt.
  2. Einen Pfad für jede existierende Textdatei.
  3. Den wörtlichen Pfad "*.txt" mit Anführungszeichen.
  4. Den wörtlichen Pfad *.txt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Was geschieht in diesem nicht interaktiven Skript?

set -eu
dest=
if [ -z "$dest" ]; then
  dest=${2:-/srv/archive}
fi
echo "$dest"

Das Skript erhält nur ein Argument, input.txt.

  1. Es stoppt, weil dest leerer Text zugewiesen wurde.
  2. Es gibt /srv/archive aus und ist erfolgreich.
  3. Es stoppt, weil das zweite Argument fehlt.
  4. Es gibt input.txt aus und ist erfolgreich.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Die Variable count enthält 10 und das aktuelle Verzeichnis ist beschreibbar und enthält keine Datei namens 4. Was geschieht?

if [ "$count" > 4 ]; then
  echo "High"
else
  echo "Low"
fi
  1. Es erstellt keine Datei und gibt High aus.
  2. Es erstellt 4 und gibt Low aus.
  3. Es erstellt keine Datei und gibt Low aus.
  4. Es erstellt 4 und gibt High aus.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Skript gleicht mit case "$value" in [0-9]*) echo "Match" ;; *) echo "No" ;; esac ab. Was geschieht bei value=8draft?
  1. Es gibt Match aus.
  2. Es gibt No aus.
  3. Es schlägt fehl, weil der Wert Buchstaben enthält.
  4. Es gibt Match und No aus.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Was wird ausgegeben?

i=0
total=0
while [ "$i" -lt 4 ]; do
  i=$(( i + 1 ))
  [ "$i" -eq 2 ] && continue
  total=$(( total + i ))
  [ "$total" -gt 5 ] && break
done
echo "$i:$total"
  1. 4:10
  2. 3:4
  3. 4:8
  4. 2:1
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Skript erhält -v, eine leere Zeichenkette in Anführungszeichen und "red room" in dieser Reihenfolge. Es führt shift und dann for arg in "$@"; do echo "<$arg>"; done aus. Was wird ausgegeben?
  1. <red>, dann <room>.
  2. <>, dann <red room>.
  3. Nur <red room>.
  4. <-v>, dann <>, dann <red room>.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Welche Tage wählt 0 11 9 * 2 /home/rae/bin/check.sh im gewöhnlichen cron?
  1. Nur Dienstage am 9., um 11:00 Uhr.
  2. Jeden Dienstag und jeden 9., um 11:00 Uhr.
  3. Jeden Dienstag im September, um 11:00 Uhr.
  4. Nur den zweiten Dienstag, um 11:09 Uhr.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein aktivierter kalenderbasierter Timer hat Persistent=true. Drei tägliche Aktivierungen verstreichen, während der Computer ausgeschaltet ist. Welches Nachholen richtet er bei erneuter Aktivierung ein?
  1. Eine Dienstaktivierung für die verpasste kalenderbasierte Arbeit.
  2. Drei Aktivierungen, eine für jeden verpassten täglichen Lauf.
  3. Keine Aktivierung bis zum nächsten zukünftigen Kalendertermin.
  4. Fortlaufende Aktivierungen, bis der Rechner herunterfährt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 5: Quoting, Fehlerprüfungen und wiederverwendbare Eingaben kombinieren10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Ein Bash-Terminal befindet sich in /home/rae, mit dem PATH /home/rae/bin:/usr/local/bin:/usr/bin:/bin. Ausführbare Bash-Skripte namens scan existieren in beiden bin-Verzeichnissen und im aktuellen Verzeichnis. Jedes enthält nur einen Bash-Shebang und cd /srv/cache; dieses Verzeichnis existiert und ist zugänglich. Welche Datei führt der erste Befehl aus und welche Pfade werden ausgegeben?

scan
pwd
source ./scan
pwd
  1. /usr/local/bin/scan; dann /home/rae und /srv/cache.
  2. /home/rae/bin/scan; dann /home/rae und /srv/cache.
  3. ./scan; dann /srv/cache und /srv/cache.
  4. /home/rae/bin/scan; dann /srv/cache und /srv/cache.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Ein Verzeichnis enthält nur a.txt und b.txt. Wie viele Datenargumente formatiert printf '<%s>\n' $value nach value="*.txt spare" bei den Standardeinstellungen von Bash für Wortaufteilung und Glob-Expansion?
  1. Eines: das wörtliche *.txt spare.
  2. Zwei: das wörtliche *.txt und spare.
  3. Drei: a.txt, b.txt, spare.
  4. Zwei: a.txt spare und b.txt spare.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein Befehl gibt ready auf der Standardausgabe und warning auf der Standardfehlerausgabe aus und ist dann erfolgreich. Was wird durch message=$(the_command) gespeichert?
  1. Nur ready.
  2. Nur warning.
  3. Beide Zeilen in Reihenfolge.
  4. Der Befehlsstatus 0.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Welcher Rückgabestatus erreicht den Aufrufer?

#!/bin/bash
false
saved=$?
true && echo "Handled"
exit $(( saved + 2 ))
  1. 0
  2. 1
  3. 2
  4. 3
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Ein Skript verwendet set -u und hat bereits folder="" zugewiesen. Es muss mit einer hilfreichen Diagnosemeldung stoppen, bevor es ein fehlendes oder leeres Verzeichnis verwendet. Welche Expansion liefert diese Prüfung?
  1. ${folder:?Folder required}
  2. ${folder:-Folder required}
  3. "$folder"
  4. ${folder}
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Welcher Test prüft, ob "$text" eine Länge ungleich null hat?
  1. [ -z "$text" ]
  2. [ -s "$text" ]
  3. [ -n "$text" ]
  4. [ -e "$text" ]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Welche Werte gibt for i in {1..$limit}; do echo "$i"; done bei limit=3 unter gewöhnlicher Bash-Expansion aus?
  1. Drei Werte: 1, 2, 3.
  2. Ein Wert: das wörtliche {1..$limit}.
  3. Keine Werte, weil die Liste leer ist.
  4. Ein Wert: das wörtliche {1..3}.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Welche Anzahl wird beim standardmäßigen Pipeline-Verhalten von Bash ausgegeben? Die Datei enthält drei Zeilen mit abschließendem Zeilenvorschub.

count=5
cat tasks.txt | while IFS= read -r line; do
  count=$(( count + 1 ))
done
count=$(( count + 2 ))
echo "$count"
  1. 10
  2. 7
  3. 8
  4. 5
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein Skript wertet seine Eingaben mit diesem Code aus und verlangt anschließend genau zwei Dateiargumente. Wie viele Argumente bleiben nach dem Aufruf ./copy.sh -v -- "early notes.txt" -final.txt und was sollte als Nächstes geschehen?

while [ "$#" -gt 0 ]; do
  case "$1" in
    -v) verbose=1; shift ;;
    --) shift; break ;;
    -*) echo "Unknown option" >&2; exit 2 ;;
    *) break ;;
  esac
done
  1. Drei bleiben; die zusätzliche Optionsendmarkierung zurückweisen.
  2. Zwei bleiben; -final.txt als unbekannte Option zurückweisen.
  3. Zwei bleiben; beide Pfade prüfen und das Kopieren versuchen.
  4. Eines bleibt; einen Standardwert für das fehlende Ziel verwenden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein zeitgesteuertes Skript verwendet Bash-Syntax und ist mit einem Bash-Shebang ausführbar. Es funktioniert im Terminal, aber cron meldet, dass ein Hilfsbefehl fehlt. Das Hilfsprogramm existiert in /home/rae/.local/bin. Welche Änderung behebt den wahrscheinlichen Unterschied?
  1. Den Bash-Shebang des Skripts in /bin/sh ändern.
  2. Ein Benutzerfeld zur persönlichen Crontab hinzufügen.
  3. Das ausführbare Skript ein zweites Mal ausführbar machen.
  4. Den absoluten Pfad des Hilfsprogramms verwenden oder den PATH von cron setzen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

76 Schlüsselbegriffe, jeweils mit Definition

A

Ablaufverfolgung
Die Ablaufverfolgung gibt Befehle nach der Expansion aus, während Bash sie ausführt, und macht die bei der Ausführung verwendeten Werte für die Fehlersuche sichtbar.
Die Ablaufverfolgung mit bash -x zeigt ein leeres Quellargument, das an einen Dateikopierbefehl übergeben wird.
Anacron
Anacron führt regelmäßige Aufgaben aus, die während einer Ausfallzeit verpasst wurden, und behandelt nach dem Start üblicherweise tägliche, wöchentliche und monatliche Arbeit.
Anacron kann eine tägliche Aufgabe auf einem Laptop nachholen, der zu ihrer üblichen geplanten Zeit ausgeschaltet war.
Argumentanzahl
Die Argumentanzahl ist die Anzahl der übergebenen Positionsargumente. Sie ist als $# verfügbar und schließt den Aufrufnamen aus.
Die Argumentanzahl für ./greet.sh Ana "Lee Kim" ist 2, weil der Name in Anführungszeichen ein Argument ist.
Argumentweitergabe
Die Argumentweitergabe übergibt die von einem Skript empfangenen Werte an einen anderen Befehl, üblicherweise mit "$@", um die einzelnen Grenzen zu erhalten.
Die Argumentweitergabe mit "$@" erhält eine leere Eingabe und einen Namen aus mehreren Wörtern als separate Argumente.
Arithmetische Expansion
Die arithmetische Expansion wertet einen ganzzahligen Ausdruck innerhalb von $(( ... )) aus und setzt den berechneten Wert in den Befehl ein.
Die arithmetische Expansion macht aus "$(( count + 1 ))" den nächsten ganzzahligen Zählerwert.
Auffangmuster
Ein Auffangmuster ist ein Muster, das auf jeden verbleibenden Wert zutrifft, üblicherweise * am Ende eines case-Blocks in Bash.
Das Auffangmuster *) meldet unbekannte Befehle, nachdem die benannten Unterbefehle geprüft wurden.
Aufrufhinweis
Ein Aufrufhinweis zeigt, wie ein Befehl aufzurufen ist, nennt erforderliche Argumente und kennzeichnet optionale oder wiederholbare Eingaben.
Der Aufrufhinweis „Usage: count.sh FILE...“ zeigt an, dass Dateieingaben wiederholt werden können.
Ausführungsrecht
Das Ausführungsrecht erlaubt einem entsprechend berechtigten Benutzer, eine Datei als Programm zu starten, auch ein Skript, dessen Shebang seinen Interpreter auswählt.
Das Hinzufügen von Ausführungsrecht mit chmod u+x job.sh ermöglicht dem Eigentümer, die Ausführung von ./job.sh zu versuchen.

B

Bash
Bash ist die Bourne Again Shell, ein Befehlsinterpreter, der interaktiv und zur Ausführung von Skripten auf Linux-Systemen verwendet wird.
Ein Skript mit [[ ... ]] wählt Bash in seinem Shebang, damit seine Bedingungssyntax verstanden wird.
Befehlssubstitution
Die Befehlssubstitution führt in der Form $(command) einen Befehl aus und setzt dessen Standardausgabe ohne abschließende Zeilenvorschübe ein.
Die Befehlssubstitution in today=$(date +%F) erfasst ein Datum zur Verwendung in einem Sicherungsdateinamen.
break
Der Befehl break verlässt die aktuelle Schleife sofort, sodass die Ausführung nach dem abschließenden Befehl dieser Schleife fortgesetzt wird.
Eine Menüschleife verwendet break, wenn der Benutzer „q“ eingibt und keine weiteren Menüoptionen gelesen werden sollen.

C

case
Ein case-Block vergleicht einen Wert der Reihe nach mit Mustern und führt die Befehle des ersten passenden Zweigs aus.
Ein case-Block kann „start“, „stop“ und einen Befehl ohne Treffer in getrennten Zweigen behandeln.
continue
Der Befehl continue überspringt die verbleibenden Befehle im aktuellen Schleifendurchlauf und fährt mit dem nächsten Durchlauf oder der nächsten Bedingungsprüfung fort.
Eine Dateischleife verwendet continue nach einer fehlgeschlagenen Schutzprüfung, sodass ihr Verarbeitungsbefehl keinen fehlenden Pfad erhält.
cron
cron ist ein Hintergrunddienst zur Zeitplanung, der Befehle startet, wenn ihre Crontab-Zeitfelder mit der aktuellen Zeit übereinstimmen.
Eine cron-Aufgabe kann montags bis freitags um 06:15 Uhr ein ausführbares Berichtsskript starten, ohne dass ein Terminal geöffnet ist.
Cron-Schrittweite
Eine Cron-Schrittweite wählt regelmäßig beabstandete Werte innerhalb eines Zeitfeldes aus und beginnt beim Bereich dieses Feldes neu, statt verstrichene Zeit zu messen.
Eine Cron-Schrittweite von */45 im Minutenfeld wählt 0 und 45 und beginnt in der nächsten Stunde wieder bei 0.
Crontab
Eine Crontab ist ein Zeitplan aus cron-Einträgen, mit fünf Zeitfeldern und einem Befehl in jeder Aufgabenzeile einer persönlichen Tabelle.
Der Befehl crontab -l zeigt die Crontab des aktuellen Benutzers an, sodass ihre Zeitpläne untersucht werden können.

D

Dateiende
Das Dateiende ist der Punkt, an dem ein Eingabestrom keine weiteren Daten enthält; read in Bash meldet einen Fehlschlag, wenn es diesen Zustand erreicht.
Am Dateiende kann ein letzter Datensatz ohne Zeilenvorschub gespeichert werden, obwohl read einen Fehlschlag meldet.
Dateinamenexpansion
Die Dateinamenexpansion ersetzt ein Dateinamensmuster ohne Quoting durch passende Pfade; Bash erhält ein Muster ohne Treffer normalerweise als wörtlichen Text.
Die Dateinamenexpansion expandiert *.log zu separaten passenden Dateinamen, bevor eine for-Schleife beginnt.
Dateiprüfung
Eine Dateiprüfung prüft Existenz, Typ oder Zugriffseigenschaften eines Pfads und liefert einen Status, den eine Bedingung verwenden kann.
Die Dateiprüfung [ -d "$src" ] akzeptiert ein Quellverzeichnis, weist aber eine reguläre Datei zurück.
Divisionsrest
Ein Divisionsrest ist der ganzzahlige Betrag, der nach einer Division ganzer Zahlen übrig bleibt; die Bash-Arithmetik ermittelt ihn mit dem Operator %.
Der Divisionsrest in $(( 17 % 5 )) ist 2, weil drei vollständige Gruppen zu je fünf den Wert 15 ergeben.
Doppelte Anführungszeichen
Doppelte Anführungszeichen erhalten Leerzeichen und Platzhalterzeichen in einem Wert und erlauben zugleich Variablen-, Befehls- und arithmetische Expansion.
Doppelte Anführungszeichen in echo "Home: $HOME *" erlauben die Expansion des Home-Pfads und erhalten das Sternchen.

E

Einfache Anführungszeichen
Einfache Anführungszeichen schließen wörtlichen Text ein und verhindern Variablen-, Befehls- und Platzhalterexpansionen innerhalb des geschützten Teils.
Einfache Anführungszeichen bewirken, dass echo '$HOME' die Zeichen „$HOME“ statt eines Home-Pfads ausgibt.
elif
Das Schlüsselwort elif leitet eine weitere Bedingung in einem if-Block ein, die nur geprüft wird, wenn alle früheren Bedingungen in diesem Block fehlgeschlagen sind.
Ein elif-Test auf 75 % Belegung läuft nur, nachdem der frühere Test auf mindestens 90 % fehlgeschlagen ist.
errexit
errexit ist die Bash-Option set -e, die bei nicht behandelten Fehlschlägen beendet und dabei bestimmte Kontexte zulässt, die den Befehlsstatus prüfen.
Die Option errexit erlaubt einer fehlgeschlagenen if-Bedingung, ihren else-Zweig auszuwählen, statt das Skript zu beenden.
exit
Der eingebaute Befehl exit beendet die Shell oder das Skript und meldet einen angegebenen Status oder den Status des vorherigen Befehls, wenn keine Zahl angegeben wird.
Ein Skript verwendet nach einem Aufruffehler exit 2, damit sein Aufrufer ein Fehlerergebnis erhält.
Export
Ein Export markiert eine Shellvariable zur Aufnahme in die Umgebung, die anschließend von dieser Shell gestartete Programme erben.
Ein Export von BACKUP_DIR ermöglicht einem neu gestarteten Sicherungsskript, das konfigurierte Ziel zu lesen.

F

Fehlerkennzeichen
Ein Fehlerkennzeichen ist ein gespeicherter Wert, der sich einen fehlgeschlagenen Teil einer größeren Aufgabe merkt, damit der abschließende Status ungleich null bleibt.
Ein Fehlerkennzeichen bleibt nach einer fehlenden Datei gesetzt, selbst wenn das Skript eine spätere Datei erfolgreich zählt.
for-Schleife
Eine for-Schleife wiederholt Befehle für jedes Element einer Liste und weist dieses Element der Schleifenvariable zu, bevor sie den Schleifenkörper ausführt.
Eine for-Schleife über web1 web2 db1 führt ihren Schleifenkörper einmal für jeden der drei Hostnamen aus.

G

Ganzzahldivision
Die Ganzzahldivision berechnet einen ganzzahligen Quotienten und verwirft den Bruchteil, statt ein Dezimalergebnis zu liefern.
Durch die Ganzzahldivision ergibt $(( 7 / 2 )) den Wert 3, obwohl der genaue Quotient 3,5 ist.

I

IFS
IFS ist die interne Feldtrennzeichenvariable der Shell; wird sie für read leer gesetzt, bleiben führender und abschließender Leerraum erhalten.
Die Verwendung von IFS= read -r line erhält Leerzeichen an den Rändern jedes aus der Eingabedatei gelesenen Datensatzes.
Interpreter
Ein Interpreter ist ein Programm, das Anweisungen in einer Sprache liest und ausführt, die es versteht.
Der durch #!/usr/bin/python3 ausgewählte Interpreter liest Python-Code statt Bash-Befehle.

K

Kalenderbasierter Timer
Ein kalenderbasierter Timer gleicht Datumsangaben und Uhrzeiten über OnCalendar ab und kann verpasste Arbeit nachholen, wenn Persistent auf true steht.
Ein kalenderbasierter Timer mit OnCalendar=Mon..Fri 09:00 wählt Montag bis Freitag morgens um 09:00 Uhr.
Kindprozess
Ein Kindprozess ist ein Prozess, der von einem anderen Prozess gestartet wird und einen eigenen Zustand sowie geerbte Umgebungswerte besitzt.
Ein Skript in einem Kindprozess kann das Verzeichnis wechseln, ohne das Verzeichnis des Terminals zu ändern, das es gestartet hat.
Klammerexpansion
Die Klammerexpansion erstellt aus einer Schreibweise wie {1..5} eine feste Liste, bevor Bash die Variablenexpansion für den Befehl ausführt.
Die Klammerexpansion kann {1..$n} nicht in einen Bereich umwandeln, der auf dem in n gespeicherten Wert beruht.
Kommentar
Ein Kommentar ist erläuternder Text, den die Shell ignoriert und der außerhalb von durch Quoting geschütztem Text an einer Wortgrenze mit # eingeleitet wird.
Der Kommentar # Keep a copy for recovery erklärt, warum das folgende Kopieren einer Datei nötig ist.
Kurzschlussauswertung
Die Kurzschlussauswertung verwendet den Status eines Befehls, um zu entscheiden, ob der nächste Befehl in einer &&- oder ||-Liste läuft.
Die Kurzschlussauswertung in cd /data || exit 1 stoppt abhängige Befehle nach einem fehlgeschlagenen Verzeichniswechsel.

L

Lingering
Lingering ermöglicht es, den systemd-Benutzermanager ohne aktive Anmeldesitzung verfügbar zu halten, damit Benutzerdienste und -Timer laufen können.
Ein Administrator aktiviert Lingering, wenn die zeitgesteuerte Aufgabe eines Benutzers ohne Anmeldung weiterlaufen muss.

M

Minimale Umgebung
Eine minimale Umgebung stellt nur eine kleine Auswahl an Prozesseinstellungen bereit, ohne die Variablen und Startdateien einer interaktiven Sitzung.
In der minimalen Umgebung von cron kann ein persönliches bin-Verzeichnis fehlen, das im Terminal verfügbar war.
Monotoner Timer
Ein monotoner Timer misst die seit einem Ereignis verstrichene Zeit, etwa seit dem Systemstart oder der letzten Dienstaktivierung, statt einen Kalenderzeitpunkt abzugleichen.
Ein monotoner Timer kann OnBootSec und OnUnitActiveSec für einen ersten Lauf und spätere Intervalle kombinieren.

N

Negation
Eine Negation kehrt Erfolg und Fehlschlag eines Befehls oder Tests um, sodass eine Bedingung Fälle auswählen kann, in denen die ursprüngliche Bedingung falsch ist.
Die Negation in [ ! -d "$p" ] akzeptiert sowohl eine reguläre Datei als auch einen Pfad, der nicht existiert.
nounset
nounset ist die Bash-Option set -u, die eine Expansion einer nicht gesetzten Variable in einem nicht interaktiven Skript als Fehler behandelt.
Bei aktiviertem nounset kann ein falsch geschriebener Variablenname ein Skript stoppen, bevor es einen leeren Pfad verwendet.
Numerischer Vergleich
Ein numerischer Vergleich wertet ganzzahlige Werte mit Operatoren wie -eq und -gt unabhängig von ihrer Textlänge aus.
Der numerische Vergleich [ "$count" -ge 8 ] ist bei einem gespeicherten Zählerwert von 12 erfolgreich.

O

Option
Eine Option ist eine Befehlszeileneingabe, die das Verhalten ändert, häufig mit einem führenden Bindestrich geschrieben und vor gewöhnlichen Argumenten abgearbeitet wird.
Die Option -v kann zusätzliche Meldungen aktivieren, bevor das Skript die verbleibenden Dateinamen verarbeitet.

P

PATH
PATH ist der durch Doppelpunkte getrennte Umgebungswert, der Verzeichnisse für die Suche nach Befehlsnamen ohne Schrägstrich auflistet.
Die Shell durchsucht PATH nach job.sh, folgt aber dem ausdrücklichen Pfad im aktuellen Verzeichnis bei ./job.sh.
pipefail
pipefail ist eine Bash-Option, die eine Pipeline den Status ihres am weitesten rechts stehenden fehlgeschlagenen Befehls oder null zurückgeben lässt, wenn jeder Befehl erfolgreich ist.
Bei aktiviertem pipefail kann eine von grep gemeldete fehlende Eingabe die gesamte Pipeline fehlschlagen lassen.
Pipeline-Rückgabestatus
Ein Pipeline-Rückgabestatus ist das Ergebnis einer Befehlspipeline, das normalerweise vom letzten Befehl stammt, sofern pipefail diese Regel nicht ändert.
Der Pipeline-Rückgabestatus kann null sein, wenn grep fehlschlägt, aber das folgende wc erfolgreich keine Eingabe zählt.
Positionsparameter
Ein Positionsparameter enthält ein an ein Skript übergebenes Argument. Die Nummerierung beginnt bei $1; für Positionen nach neun sind geschweifte Klammern nötig.
Der Positionsparameter ${10} ruft das zehnte Argument ab, ohne eine Null an $1 anzuhängen.

Q

Quoting
Quoting steuert, wie Bash Sonderzeichen interpretiert, und hält den beabsichtigten Text zusammen, während Bash Befehlsargumente vorbereitet.
Das Quoting von "$file" erhält „monthly report.txt“ beim Kopieren der Datei als ein Argument.

R

read
Der in Bash eingebaute Befehl read liest eine Zeile aus der Standardeingabe und speichert ihre Felder in den im Befehl genannten Variablen.
Mit read -r -p "Name: " name wird ein Name abgefragt und Backslashes im eingegebenen Text bleiben erhalten.
Rückgabestatus
Ein Rückgabestatus ist ein ganzzahliges Befehlsergebnis von 0 bis 255; null bedeutet Erfolg und andere Werte melden dokumentierte Ergebnisse.
Der Rückgabestatus von grep -q unterscheidet einen Treffer, keinen Treffer und ein Problem beim Lesen der Eingabe.

S

Schleifendurchlauf
Ein Schleifendurchlauf ist ein einmaliges Durchlaufen des Schleifenkörpers mit dem aktuellen Listenelement oder den aktuellen Werten, bevor der nächste Durchlauf beginnt.
Ein Durchlauf einer Dateischleife verarbeitet den einzelnen Namen „beach day.jpeg“, bevor es weitergeht.
Schlüsselwort für Bedingungen
Ein Schlüsselwort für Bedingungen wie [[ von Bash beginnt ein Shelltest-Konstrukt mit eigenen Regeln für die Auswertung und den Musterabgleich.
Das Schlüsselwort für Bedingungen [[ erlaubt [[ $name == *.log ]] ohne Wortaufteilung des Namens.
Service-Unit
Eine Service-Unit definiert Arbeit, die systemd starten soll, etwa ein einmalig laufendes Skript, das durch einen absoluten ExecStart-Pfad angegeben wird.
Die Service-Unit backup.service definiert das Skript, das vom passenden Sicherungstimer aktiviert wird.
Shebang
Ein Shebang ist die mit #! beginnende erste Zeile, die den Interpreter nennt, den Linux zum Ausführen eines Skripts verwenden soll.
Der Shebang #!/bin/bash beginnt beim ersten Zeichen, vor jedem Kommentar und jeder Leerzeile.
Shellskript
Ein Shellskript ist eine reine Textdatei mit Shellbefehlen, die gespeichert werden, damit ein Interpreter sie als wiederholbare Aufgabe ausführen kann.
Ein Shellskript kann ein Sicherungsverzeichnis anlegen, Notizen hineinkopieren und die gespeicherte Kopie auflisten.
shift
Der eingebaute Befehl shift entfernt vordere Positionsparameter und nummeriert die verbleibenden neu, wodurch sich die Argumentanzahl verringert.
Nachdem shift -v abgearbeitet hat, wird das nächste Befehlszeilenwort für die Optionsauswertung zu $1.
Sourcing
Sourcing bedeutet, die Befehle einer Datei in die aktuelle Shell einzulesen, sodass ihre Zuweisungen und Verzeichniswechsel diese Shell beeinflussen.
Das Einlesen von ./settings.sh mit source lädt dessen Variablenzuweisungen direkt in die offene Bash-Sitzung.
Standardfehlerausgabe
Die Standardfehlerausgabe ist der Ausgabestrom für Diagnosemeldungen, getrennt von der Standardausgabe, sodass normale Daten unabhängig umgeleitet werden können.
Eine mit >&2 an die Standardfehlerausgabe gesendete Meldung bleibt sichtbar, wenn die Standardausgabe in eine Datei geht.
Standardwert
Ein Standardwert liefert eine optionale Eingabe, wenn kein brauchbarer Wert angegeben wurde, etwa ${1:-/var/log} bei einem fehlenden oder leeren Argument.
Ein Standardwert ermöglicht es einem zeitgesteuerten Bericht, ein Standardverzeichnis zu verwenden, ohne eine Person zu fragen.
Suffixentfernung
Die Suffixentfernung ist eine Parameterexpansion, die eine passende Endung aus dem Wert einer Variable entfernt, wie in ${f%.jpeg}.
Die Suffixentfernung macht aus „lake.jpeg“ den Namen „lake“, sodass ein Umbenennungsbefehl anschließend „.jpg“ anhängen kann.
Syntaxprüfung
Eine Syntaxprüfung liest ein Skript, um fehlerhafte Shellstrukturen zu finden, ohne die Befehle auszuführen oder ihre tatsächlichen Ergebnisse zu prüfen.
Eine Syntaxprüfung mit bash -n erkennt ein fehlendes done, bevor die Schleife Befehle ausführen kann.
systemd-Journal
Das systemd-Journal speichert Dienstausgaben und Diagnoseeinträge, sodass zeitgesteuerte Arbeit nach ihrer Ausführung untersucht werden kann.
Die Journalabfrage journalctl -u backup.service zeigt Meldungen der Sicherungsaufgabe.

T

Timer-Unit
Eine Timer-Unit liefert einen systemd-Zeitplan, der eine andere Unit aktiviert, normalerweise den Dienst mit demselben Grundnamen.
Die Aktivierung der Timer-Unit backup.timer richtet den Zeitplan für den Sicherungsdienst ein.
Trap
Ein Trap registriert einen Befehl, der bei einem ausgewählten Signal oder Shellereignis ausgeführt wird, etwa bei EXIT, wenn der Bash-Prozess endet.
Ein EXIT-Trap kann die temporäre Datei entfernen, deren Pfad zuvor im Skript gespeichert wurde.

U

Umgebungsvariable
Eine Umgebungsvariable ist ein benannter Wert in der Umgebung, die von einem Prozess an die von ihm gestarteten Programme kopiert wird.
Die Umgebungsvariable HOME liefert vielen Befehlen, die eine Shell startet, einen Pfad zum Home-Verzeichnis.
until-Schleife
Eine until-Schleife prüft vor jedem Durchlauf einen Befehl und wiederholt ihren Schleifenkörper, bis dieser Befehl Erfolg zurückgibt.
Eine until-Schleife kann zwischen Prüfungen pausieren, während sie auf eine Datei wartet, die den Abschluss eines Exports anzeigt.

V

Validierung
Die Validierung prüft vor Beginn abhängiger Arbeit, ob Eingaben die Anforderungen eines Skripts erfüllen, einschließlich Anzahl und Typ der Argumente.
Die Validierung weist ein Verzeichnis zurück, wenn ein Zählskript eine reguläre Datei als Eingabe verlangt.
Variable
Eine Variable ist ein von der Shell gespeicherter benannter Wert, der expandiert wird, wenn ein Befehl den diesem Namen zugeordneten Wert benötigt.
Die Variable city speichert nach city=Lisbon den Wert „Lisbon“, sodass echo "$city" ihn anzeigen kann.
Variablenexpansion
Die Variablenexpansion ersetzt einen Namen mit vorangestelltem Dollarzeichen durch seinen gespeicherten Wert, während Bash einen Befehl zur Ausführung vorbereitet.
Die Variablenexpansion macht aus "${file}_old" den Wert „report_old“, wenn file den Wert „report“ enthält.

W

while-Schleife
Eine while-Schleife prüft vor jedem Durchlauf einen Befehl und wiederholt ihren Schleifenkörper, solange dieser Befehl Erfolg zurückgibt.
Eine while-Schleife, die eine Datei liest, endet, wenn read das Dateiende erreicht und einen Fehlschlag meldet.
Wortaufteilung
Die Wortaufteilung zerlegt eine Expansion ohne Quoting anhand von Trennzeichen in einzelne Wörter, normalerweise an Leerzeichen, Tabulatoren und Zeilenvorschüben.
Die Wortaufteilung macht aus einem Wert „my report.txt“ ohne Quoting zwei Argumente, bevor cp läuft.

Z

Zähler
Ein Zähler ist eine gespeicherte Zahl, die bei Ereignissen oder Schleifendurchläufen aktualisiert wird, häufig indem eins zu ihrem vorherigen Wert addiert wird.
Ein mit count=0 initialisierter Zähler kann für jede Zeile, die eine Schleife liest, einmal erhöht werden.
Zeichenkettenvergleich
Ein Zeichenkettenvergleich prüft Text Zeichen für Zeichen, sodass unterschiedliche Schreibweisen oder führende Nullen Werte ungleich machen können.
Ein Zeichenkettenvergleich behandelt „07“ und „7“ als verschieden, obwohl sie dieselbe ganze Zahl darstellen.
Zeilenende
Ein Zeilenende markiert das Ende einer Textzeile; Unix verwendet einen Zeilenvorschub, während Windows üblicherweise einen vorangestellten Wagenrücklauf ergänzt.
Ein Windows-Zeilenende in einem Shebang kann dazu führen, dass Linux nach einem Interpreterpfad sucht, der auf ^M endet.
Zuweisung
Eine Zuweisung speichert einen Wert mit name=value unter einem Variablennamen, ohne Leerzeichen um das Gleichheitszeichen.
Die Zuweisung name="Lee Kim" hält die beiden Wörter als einen gespeicherten Wert zusammen.
Zweig
Ein Zweig ist eine Gruppe von Befehlen, die durch eine Bedingung oder einen Musterabgleich ausgewählt wird und einem Skript unterschiedliche Aktionen für unterschiedliche Eingaben ermöglicht.
Ein Zweig für den höchsten Schwellenwert der Speicherplatzbelegung muss vor einem überlappenden Warnschwellenwert stehen.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten