Metazeichen und Quoting
Die Shell ersetzt, bevor das Programm startet
Abschnitt betitelt „Die Shell ersetzt, bevor das Programm startet“Schritt 4 der Arbeitsweise: Bevor die Shell ein Programm aufruft, ersetzt sie bestimmte Zeichen in der Befehlszeile. Das Programm sieht nur das Resultat. Wenn du ls *.txt tippst, bekommt ls nie den Stern zu sehen, sondern die fertige Liste a.txt b.txt c.txt. Diese Zeichen mit Sonderbedeutung heissen Metazeichen. Wer sie kennt, kann sie gezielt einsetzen und bei Bedarf gezielt abschalten.
Verzeichnis-Abkürzungen
Abschnitt betitelt „Verzeichnis-Abkürzungen“| Zeichen | Bedeutung |
|---|---|
~ |
Dein Home-Verzeichnis, ~anna das von anna |
. |
Das aktuelle Verzeichnis |
.. |
Das übergeordnete Verzeichnis |
- |
Bei cd -: das vorherige Verzeichnis |
~ wird nur am Anfang eines Wortes ersetzt. echo ~/bin gibt /home/du/bin, aber echo "~/bin" gibt ~/bin. Diesen Stolperstein triffst du gleich noch einmal.
Globs: Muster für Dateinamen
Abschnitt betitelt „Globs: Muster für Dateinamen“| Muster | Bedeutung | Beispiel | Passt auf |
|---|---|---|---|
* |
beliebig viele Zeichen, auch keines | *.conf |
hosts.conf, .conf |
? |
genau ein Zeichen | Radiu? |
Radius, Radium |
[abc] |
eines der aufgezählten Zeichen | tty[123] |
tty1, tty2, tty3 |
[a-z] |
eines aus dem Bereich | [a-c]* |
alles, das mit a, b oder c beginnt |
[!a-z] oder [^a-z] |
keines der Zeichen | D[!0-9]L |
DaL, aber nicht D3L |
Die Shell sucht alle Dateinamen, die auf das Muster passen, und setzt sie alphabetisch sortiert an die Stelle des Musters. Zwei Regeln, die oft überraschen:
*passt nicht auf Dateien, die mit einem Punkt beginnen. Versteckte Dateien brauchen.*oder.bash*.- Passt kein Dateiname, bleibt das Muster unverändert stehen und das Programm bekommt den Stern wörtlich.
ls *.xyzmeldet danncannot access '*.xyz'.
Hands-on: echo ist das beste Werkzeug, um zu sehen, was die Shell aus einem Muster macht, bevor du es an rm oder mv übergibst.
cd /etcecho *.confecho host?ls -d [a-d]*ls -d [!a-z]*ls /dev/tty[0-3]echo *.xyzBrace Expansion
Abschnitt betitelt „Brace Expansion“Geschweifte Klammern erzeugen Wortvarianten. Anders als Globs schauen sie nicht ins Dateisystem, sondern produzieren einfach Text:
echo {a,b,c}echo datei.{txt,md,pdf}echo {1..5}echo {01..10}echo {a..e}Das ist praktisch, um Strukturen anzulegen oder Backups zu benennen:
mkdir -p ~/projekt/{src,docs,tests}ls ~/projekttouch ~/projekt/docs/kapitel-{1..3}.mdcp /etc/hosts /tmp/hosts.bakcp /tmp/hosts{.bak,.kopie}Die letzte Zeile wird zu cp /tmp/hosts.bak /tmp/hosts.kopie. Ein Alltags-Trick: cp datei.conf{,.bak} erzeugt datei.conf.bak.
Das Escape-Zeichen
Abschnitt betitelt „Das Escape-Zeichen“Ein Backslash \ nimmt dem nächsten Zeichen seine Sonderbedeutung:
cd /tmptouch 'alle*imAll.txt' alle8imAll.txtls alle*imAll.txtls alle\*imAll.txtrm alle\*imAll.txt alle8imAll.txtDer dritte Befehl zeigt beide Dateien, der vierte nur die mit dem wörtlichen Stern. Ein Backslash am Zeilenende hebt den Zeilenumbruch auf, damit kannst du lange Befehle über mehrere Zeilen schreiben.
Die drei Arten von Quoting
Abschnitt betitelt „Die drei Arten von Quoting“Statt jedes Zeichen einzeln zu maskieren, setzt du Anführungszeichen. Es gibt drei Varianten mit klaren Regeln:
| Art | Was die Shell noch ersetzt | Typischer Einsatz |
|---|---|---|
'...' einfach |
nichts, jedes Zeichen bleibt wörtlich | Suchmuster für grep, sed, awk, feste Texte |
"..." doppelt |
$ (Variablen, $(...)), ` und \ |
alles, was Variablen enthält |
\ Backslash |
nur das eine folgende Zeichen bleibt wörtlich | einzelnes Sonderzeichen |
Innerhalb beider Arten von Anführungszeichen bleiben Leerzeichen, Globs und Klammern erhalten. Der einzige Unterschied ist, ob $ noch arbeitet.
Hands-on:
echo $HOMEecho "$HOME"echo '$HOME'echo \$HOMEecho "Mein Home ist $HOME, *.conf bleibt stehen"echo 'Preis: 5$ (ohne Variable)'echo "Anführungszeichen \"innen\" gehen mit Backslash"echo 'Ein Apostroph geht nicht in '\''einfachen'\'' Anführungszeichen'Die letzte Zeile ist der bekannte Trick: Ein Apostroph in einfachen Anführungszeichen schreibt man als '\'' (Quoting schliessen, Apostroph maskieren, Quoting öffnen). In der Praxis nimmst du in diesem Fall besser doppelte Anführungszeichen.
Kommandosubstitution
Abschnitt betitelt „Kommandosubstitution“$(befehl) wird durch die Ausgabe des Befehls ersetzt. So landet ein Resultat in einer Variable oder mitten in einem Satz:
echo "Heute ist $(date +%A), es ist $(date +%H:%M) Uhr"anzahl=$(ls /etc | wc -l)echo "In /etc liegen $anzahl Einträge"echo "Kernel: $(uname -r) auf $(hostname)"Die ältere Schreibweise mit Backticks `befehl` siehst du noch in vielen alten Skripten. Sie funktioniert, lässt sich aber schlecht verschachteln und ist leicht mit einfachen Anführungszeichen zu verwechseln. Schreibe immer $(...).
Warum Variablen in Anführungszeichen gehören
Abschnitt betitelt „Warum Variablen in Anführungszeichen gehören“Jetzt kommt das Zusammenspiel von Schritt 1 (Wörter trennen) und Schritt 4 (ersetzen). Die Shell ersetzt zuerst die Variable und zerlegt das Resultat danach an Leerzeichen in Wörter. Ohne Anführungszeichen wird aus einem Dateinamen mit Leerzeichen plötzlich zwei Argumente.
Hands-on:
cd /tmpdatei="Mein Bericht.txt"touch "$datei"ls -l $dateils -l "$datei"Was erwartest du? Der erste ls sucht zwei Dateien, Mein und Bericht.txt, und findet keine davon. Der zweite findet die richtige. Dasselbe gilt für rm, mv, cp und jedes Skript. Darum lautet die Regel:
Auch bei Schleifen über Dateien zahlt sich das aus. Globs liefern die Namen korrekt, selbst mit Leerzeichen, solange du die Variable in der Schleife wieder quotest:
touch "Zweiter Bericht.txt"for f in *.txt; do echo "Datei: $f"; donerm "Mein Bericht.txt" "Zweiter Bericht.txt"echo oder printf
Abschnitt betitelt „echo oder printf“echo reicht für einfache Meldungen. Sobald Formatierung oder Zeichen wie \n ins Spiel kommen, verhält sich echo je nach Shell unterschiedlich. printf funktioniert überall gleich und kennt Formatangaben wie in C oder Python:
printf 'Name: %s, Alter: %d\n' "Anna" 17printf '%-12s %6s\n' "Datei" "Grösse"printf '%-12s %6d\n' "hosts" 221 "passwd" 2856printf '%s\n' "$HOME" "$USER"%s ist ein Text, %d eine ganze Zahl, %-12s ein linksbündiger Text mit zwölf Zeichen Breite. Das Format kommt in einfache Anführungszeichen, die Werte dahinter in doppelte. Hat printf mehr Werte als Platzhalter, wiederholt es das Format, darum gibt die letzte Zeile zwei Zeilen aus.
Lösung anzeigen
cd /tmpmkdir -p kurs/modul-0{1..5}ls kurstouch kurs/modul-0{1..5}/{notizen,aufgaben}.mdfind kurs -type f | wc -lls -d kurs/modul-0[24]echo 'Der Wert von $HOME ist '"$HOME"# Antwort 4: einfache Anführungszeichen für den festen Teil mit $, doppelte für die Variable.# Geht auch: echo "Der Wert von \$HOME ist $HOME"datei="Mein Protokoll.txt"touch "$datei"ls -l $dateils -l "$datei"# Antwort 5: Ohne Anführungszeichen zerlegt die Shell den Wert an Leerzeichen in zwei Argumente,# ls sucht darum "Mein" und "Protokoll.txt" und findet keines von beiden.printf '%-10s %s\n' "$USER" "$HOME"rm -r kurs "Mein Protokoll.txt"Selbstcheck · 6 Fragen
Weiterführend
Abschnitt betitelt „Weiterführend“man bash, Abschnitte «QUOTING» und «EXPANSION»- Bash Reference Manual: Quoting
- ShellCheck SC2086, warum Variablen Anführungszeichen brauchen