Wissen/Bourne Shell
Aus UUGRN
< Wissen
Bourne-Shell: Geschichte und Grundlagen
- Datum: 5. Februar 2021
- Referent: Tilman Kranz tilt@linuxfoo.de
- Ca. 120 Minuten
Teil 1: Geschichte
Thompson-Shell
- Erste Shell für AT&T UNIX (“UNICS”) Version 1 bis 6
- Name des Programms: “sh” (liegt im Verzeichnis “/bin”). Also lautet der absolute Pfadname
/bin/sh
, - Aufgaben:
- Starten von Programmen
- Umleiten von Ausgaben (“Redirection”) in andere Programme (“Filter”) oder in Dateien.
- Siehe auch Manpage https://www.in-ulm.de/~mascheck/bourne/v3/
Bourne-Shell
- Nachfolger der Thompson-Shell ab AT&T UNIX Version 7.
- Hauptaugenmerk auf “Command Language” (mit Bedingunge, Schleifen u.v.a.m.).
- Syntax der Sprache inspiriert von ALGOL68.
- Außerdem können Shell-Skripte selbst Filter sein (ging bei Thompson Shell nicht).
- Seit 1989 quasi quasi unverändert, vergleiche auch: https://en.wikipedia.org/wiki/Bourne_shell#Features_introduced_after_1979
- Code der Bourne Shell war die Inspiration für den International Obfuscated C Code Contest".
C-Shell
- Entwickelt von der “Berkeley Group” (BSD) als Alternative zu Bourne Shell.
- Inspiriert von C-Syntax.
- Komfortabler als die Bourne Shell für interaktive Benutzung.
- Gilt inzwischen als veraltet (“C Shell Programming considered harmful”).
Korn-Shell
- Kompatibel zur Bourne-Shell.
- Mehr Funktionen.
- Sehr viel besser für interaktive Benutzung:
- History
- Commandline editing,
- Job-Kontrolle.
- Wichtige Versionen:
- 88: Grundlage für POSIX:
- 93: Kompletter Rewrite, viel mächtiger, verbraucht aber viel mehr Speicher und CPU.
Bourne-Again-Shell
- Auftragsarbeit eines Festangestellten der Free Software Foundation für das GNU-Projekt.
- Auf BSD nicht standardmäßig installiert bzw. oft in
/usr/local/bin
o.ä.
- Auf BSD nicht standardmäßig installiert bzw. oft in
- Kompatibel zu Bourne Shell:
- Spezieller Kompatibilitätsmodus wenn als “sh” aufgerufen
- Arrays.
- “shopt” statt “set” für Bash-spezifische Optionen
- Stark erweiterte Parameter-Expansion
- z.B. Substitution,
- Siehe Manpage.
- Verbesserte Arithmetik.
- Erweiterte Redirection.
- Sehr stark verbesserter interaktiver Modus ähnlich Korn Shell.
Almquist-Shell (“ash” bzw. “dash”)
- Reimplementation der Bourne Shell unter anderer Lizenz.
- Zuerst für BSD, später portiert auf Debian (dort “dash”).
Z-Shell
- Reimplementation der Bourne Shell mit stark erweiterten Features.
- Empfohlen als interaktive, nicht aber als nicht-interaktive Shell.
- Grund: Shell-Skripte in zsh setzen installierte zsh voraus.
Kompatibilität
- Kern: Bourne Shell (und deshalb meine Empfehlung).
- Vorsicht: In "Bourne-kompatiblen" Shells kann man Code schreiben, der in Bourne nicht geht.
Teil 2: Grundlagen
Funktionsweise
- Betriebsmodus “interaktiv”.
- Spezialfall “Login-Shell”.
- Zeilenweise Ein- und Ausgabe über ein tty (“Teletype”, Printer, serielle Schnittstelle, Terminal, Terminal Emulator).
- Betriebsmodus “non-interaktiv”
- “Shebang”-Konvention in Skripten (erste Zeile
#!/bin/sh
). - Kommentare
- Line Continuation
- Shell-Optionen, die den Betriebsmodus verändern (z.B.
-e
,-x
) - Zeilenbasierter Parser
- Expansionen
- Siehe dazu z.B. die Manpage von “dash”, Abschnitt “Word Expansions”
- Kontrollstrukturen
- Redirection und Pipes
Grundsätzliche Features
- “Strings are first-class citizens and the only citizens” – Stephen Bourne
- Es gibt kein “goto” (Bourne ist ALGOL-Fan)
- Hauptaufgaben:
- Zuweisungen
- Spezialfall: “export”
- Kommandos ausführen
- builtins vs. executables
- Zuweisungen
- Variablen:
- Einfach: “foo=bar”
- Export an Subprozesse: “export FOO=bar”
- Zugriff auf den Wert der Variable:
echo "$foo"
(“verkürzte Syntax”)echo "${foo}"
(“vollständige Syntax”)
- Variablen mit Bedeutung für die Shell selbst (Beispiele): $PATH, $PS1, $IFS, …
- “Interessante” Umgebungsvariablen: $PATH, $USER, $SHELL, $PPID, …
- Expansion:
- Gute Übersicht:
https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html
- Besonders wichtig: Parameter-Expansion:
- Kommandozeilen-Argumente
$*
,$@
und$0
,$1
, … - Spezial-Features mit “ausführlicher Syntax”:
config=${1:-config.inc}
:
- Kommandozeilen-Argumente
- Besonders wichtig: Parameter-Expansion:
“Der Wert der Variable”config" ist der Wert des ersten Kommandozeilen-Arguments, es sei denn, dieses wäre leer oder nicht gesetzt, dann soll der Wert ‘config.inc’ lauten."
- Bourne Shell hat noch andere interessante Parameter-Exansion-Tricks, und Bourne Again Shell noch viel mehr.
- Wichtig: Command Substitution:
- Mit Backticks:
output=`ls | grep foo`
- oder mit Klammerung:
output=$(ls | grep foo)
- Die geklammerte Syntax hat u.a. den Vorteil, dass sie einfacher verschachtelt werden kann.
- Nützlich: Arithmetik (nur Ganzzahlen):
a=0 ; a=$((a+2)) ; echo $a
- Arbeiten mit Rückgabewerten
- Abgespeichert in
$?
- Konvention: 0: Erfolg; Sonst: Fehler.
- Abgespeichert in
- Quotierung
- Klassisch mit
"
, desweiteren auch mit'
- Spezialfall: Here-Documents
- Klassisch mit
sed -e 's/foo/bar/g' << EOF Ein foo kam daher zum foo und danach noch zu einem anderen foo. EOF
- Hinweis: Here-Documents kamen im Vortrag aus Zeitgründen nicht dran.
- Herausforderung: Escaping:
- Beispiel 1:
echo "\"Doppelte\" Anführungszeichen"
- Beispiel 2:
echo '\'Einfache\' Anführungszeichen'
- Kontrollstrukturen:
if true ; then echo "passt." ; else echo "komisch" ; fi
- bzw. auf mehreren Zeilen:
if true ; then echo "passt" else echo "komisch" fi
while true ; do echo "idle ..." ; sleep 1 ; done
- bzw.
while true ; do echo "idle ..." done
- Generell:
- Interaktiver Modus: Einzeiler-Syntax.
- Non-Interaktiver Modus/Skript: Mehrzeilige Syntax.
- Funktionen definieren
- Bourne und Bourne Again Shell:
xxx() { echo "xxx" ; }
- Nur Bourne Again Shell:
function xxx() { echo "xxx" ; }
- Empfehlung: Bourne Syntax verwenden, da vorwärtskompatibel.
- Bourne und Bourne Again Shell:
- Source Files
- Hinweis: Kam im Vortrag aus Zeitgründen nicht dran.
- Inhalt einer anderen Datei an dieser Stelle komplett als Shellcode laden und ausführen.
- Beispiel:
. /usr/local/lib/shell-stuff/config.sh
- Problem (u.a.):
. ./config.sh
(Welcher Speicherort von “config.sh” wird hier erwartet?)
Anhang: Das Beispiel "deltmp.sh" aus dem Vortrag
#!/bin/sh # set -e dir=${1:-/tmp} if find "$dir" -name '*.tmp' > /tmp/find.log 2> /tmp/find.err ; then echo "Ausgabe abgeschlossen am $(date)" >> /tmp/find.log else echo "Fehler beim Durchsuchen am $(date)" >> /tmp/find.log fi
Links
Geschichte
- Die (vereinfachte) Evolution der UNIXe und UNIX-artigen Betriebssysteme: https://upload.wikimedia.org/wikipedia/commons/7/77/Unix_history-simple.svg
- Grundsätzliche Funktionsweise (Diagramm): https://developer.ibm.com/developer/default/tutorials/l-linux-shells/images/figure2.gif
- Ken Thompson, Entwickler der ersten UNIX-Shell: https://de.wikipedia.org/wiki/Ken_Thompson
- Handbuch für “sh” (Thompson-Shell) in UNIX Version 3 (1973): https://www.in-ulm.de/~mascheck/bourne/v3/
- Vortrag von Stephen Bourne, Entwickler der Bourne-Shell: https://www.youtube.com/watch?v=2kEJoWfobpA
- “Csh Programming Considered Harmful”: https://www-uxsup.csx.cam.ac.uk/misc/csh.html
- Historische Shells praktisch ausprobieren: https://unix50.org/
Benutzung
- POSIX, Abschnitt “Shell Command Language” (aka “POSIX-Shell”): https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
- Manpage der “Debian Almquist Shell”: https://linux.die.net/man/1/dash
- Manual der Bourne Again Shell, Abschnitt “Expansions”: https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html