![]() |
Vorlesung "UNIX"von Prof. Jürgen Plate |
Die Shell ist der Kommandointerpreter von UNIX. Es haben sich drei Typen entwickelt:
UNIX-Benutzer sind "mündig"! Was heißt das? Wenn Sie ein Kommando eingeben, das die gesamte Platte löscht, fragt das Programm nicht noch einmal nach, ob Sie das auch wirklich wollen, sondern löscht die Platte sofort.
Beim Testen von Shell-Programmen hilft das Kommando
echo [Argumente]
Dieses Kommando gibt die Argumente auf dem Bildschirm aus. Für den Einsteiger ist das Kommando wichtig, weil er so die Kommandobearbeitung der Shell recht gut verfolgen und studieren kann (Einstreuen von echo-Kommandos in die Befehlsfolge).
Die Eingabeumleitung erfolgt durch das Zeichen "<", gefolgt von einem Dateinamen.
Kommando < Dateiname
Statt z. B. beim write-Kommando den Text direkt einzugeben, kann auch einen Datei an ein anderes Terminal gesendet werden:
write markus < Nachricht
Falls die Datei noch nicht vorhaden war, wird sie automatisch angelegt. Falls die Datei schon vorhanden ist, wird sie überschrieben, d. h. es wird immer ab dem Dateianfang geschrieben.
Kommando > Dateiname
Fehlermeldungen (stderr) erscheinen nach wie vor auf dem Bildschirm. Beispiel: Ausgabe der Verzeichnisbelegung in einen Datei:
ls -l > info
Kommando 2> Fehlerdatei
(Die Umleitung der Standardausgabe ist nur die Kurzform von Kommando 1> Dateiname). Natürlich ist eine beliebige Kombination von Ein- und Ausgabeumleitung möglich, z. B.
Kommando < Eingabedatei > Ausgabedatei 2> Fehlerdatei
Kommando >> Sammeldatei
Dazu ein paar Beispiele:
Dateiliste und aktive Benutzer in einen Datei schreiben:
ls -l > liste
who >> liste
Dur Umleitung von Ein- und Ausgabe läßt sich auch unterdrücken. Für die Ausgabe schreibt man
Kommando > /dev/null
oder für die Fehlerausgabe
Kommando 2> /dev/null.
Beides läßt sich auch kombinieren:
Kommando > Ergebnisdatei 2> /dev/null.
Will man ein Programm mit einem beliebigen Eingabedatenstrom versorgen, schreibt man
Kommando < /dev/zero.
Die Umleitung von stout und stderr in dieselbe Datei würde prinzipiell eine zweimalige Angabe der Datei (eventuell mit einem langen Pfad) erfordern. Für die Standarddateien werden in solchen Fällen spezielle Platzhalter verwendet:
&0 | Standardeingabe |
&1 | Standardausgabe |
&2 | Standard-Fehlerausgabe |
Kommando > ausgabe 2>&1
Wenig bekannt ist der Bourne-Shell-Operator <>. Er öffnet eine Datei zum Lesen und Schreiben und verbindet sie mit der Standardeingabe. Fehlende Dateien legt er automatisch an, im Gegensatz zu > löscht er jedoch nicht den Inhalt bestehender Dateien. Gut eignet sich <> vor allem für den Zugriff auf Geräte, die eine bidirektionale Verbindung voraussetzen - etwa Terminals oder Modems.
Die Bourne-Shell kann noch mehr: Man kann einen beliebigen Kommunikationskanal umlenken, indem er dessen Kennzahl direkt vor das Größer oder Kleiner-Zeichen schreibt. Wie schon erwähnt, steht '0' für die Standardeingabe, 'l' und '2' stehen für die Standard- beziehungsweise Fehlerausgabe.
Allgemein gilt also:
Mit den Bourne-Shell-Operatoren <& und >& lassen sich Ein- und
Ausgabekanäle miteinander verbinden. Vor dem Operator darf die Nummer des
umgeleiteten Kanals stehen, dahinter muß die des Quell- beziehungsweise
Zielkanals folgen. Die häufigste Konstruktion >datei 2>&1 leitet
Standard- und Fehlerausgabe in dieselbe Datei um.
Kommando 1 | Kommando 2
Beispiel: Ausgabe der Dateien eines Verzeichnisses mit der Möglichkeit, zu blättern:
Natürlich können auch mehrere Kommandos hintereinander durch Pipes verbunden werden:
Kommando 1 | Kommando 2 | Kommando 3 | Kommando 4 | ...
Solche Kommandofolgen werden auch als Filter bezeichnet. Einige nützliche Filter sind in jedem UNIX-System verfügbar. Zum Beispiel:
head [-n] [datei(en)]
Ausgabe der ersten n Zeilen aus den angegebenen Dateien. Voreinstellung ist 10
Zeilen. Wird keine Datei angegeben, liest head von der Standardeingabe.
tail [-/+n] [bc[f|r]] [datei]
Ausgabe der letzten n Zeilen einer Datei. Voreinstellung für n ist 10. Wird
keine Datei angegeben, liest tail von der Standardeingabe.
Optionen | |
+n | ab der n. Zeile ausgeben |
-n | die letzten n Zeilen ausgeben Wird hinter die Zahl n ein 'b' gesetzt (z. B. -15b), werden nicht n Zeilen, sondern n Blöcke ausgegeben. Wird hinter die Zahl n ein 'c' gesetzt (z. B. -200c), werden nicht n Zeilen, sondern n Zeichen (characters) ausgegeben. |
-r | Zeilen in umgekehrter Reihenfolge ausgeben (letzte zuerst). Geht nicht bei GNU-tail - stattdessen kann man das Programm toc verwenden. |
-f | tail am Dateiende nicht beenden, sondern auf weitere Zeilen warten. (Ende des Kommandos mit der CTRL-C-Taste). Damit kann man z. B. Logfiles beobachten, die ständig wachsen. |
tee [-i] [-a] [datei]
Pipe mit T-Stück: Kopiert von stdin nach stdout und schreibt die Daten gleichzeitig
in die angegebene Datei.
Optionen | |
-i | Ignorieren von Interrupts (Unterbrechungs-Taste) |
-a | Anhängen der Info an die angegebene Datei (Voreinstellung: Überschreiben der Datei) |
wc [-lwc] [Datei(en)]
Dieses Kommando zählt Zeilen, Worte oder Zeichen in einer Datei. Wird kein
Dateiname angegeben, liest wc von der Standardeingabe. Normalerweise zählt
man damit in Skripten irgendwelche Ergebnisse. Optionen:
-l | Zähle Zeilen |
-w | Zähle Worte |
-c | Zähle Zeichen |
Weitere Filter sind more, less, tr, ....
Eine wichtige Rolle spielt bei Bourne-kompatiblen Shells die Reihenfolge der Umleitungen. Mehrere Umleitungen innerhalb eines Befehls führt die Shell nacheinander aus, und zwar in Schreibrichtung von links nach rechts. Stehen Umleitungen hinter einem zusammengesetzten Befehl, etwa einer Schleife, gelten sie für das gesamte Konstrukt; sie lassen sich jedoch innerhalb der Schleife durch weitere Umleitungen zeitweilig außer Kraft setzen. Pipelines haben Vorrang vor anderen Formen der Ein- und Ausgabeumleitung. Bevor die Shell mit der Ausführung der Einzelbefehle und der dazugehörenden Umleitungen beginnt, baut sie die gesamte Pipeline zusammen: Sie erzeugt für jeden Abschnitt einen neuen Prozeß und verbindet die Standardausgabe jedes Prozesses mit der Standardeingabe des Nächsten. Will der Anwender die Fehlerausgabe eines Programms ebenfalls durch die Pipeline schicken, kann er in Bourne-Shell-Skripten
foo 2>&1 | barschreiben. Da die Shell die Pipeline-Verbindung zuerst herstellt, landen die Fehlermeldungen vom Programm foo auf der Standardeingabe von bar. Es ist auch möglich, denselben Kanal in einem Befehl mehrmals umzuleiten. Dabei gilt, daß die jeweils zuletzt ausgeführte Ein- oder Ausgabeumleitung Vorrang hat. Das Kommando
cat <a <b >c >dkopiert den Inhalt der Datei b in die Datei d. Als Seiteneffekt legt es eine leere Datei c an oder löscht den Inhalt von c, falls die Datei schon existierte.
Mitunter genügen die drei Standard-Kommunikationskanäle nicht, um eine Aufgabe zu erfüllen. Soll ein Skript etwa den Inhalt dreier Dateien miteinander vermengen, benötigt es zusätzliche Eingabekanäle. In der Bourne-Shell lassen sich weitere Kanäle mit den normalen Umleitungsoperatoren öffnen; der Benutzer muß lediglich die Nummer des gewünschten Kanals angeben. Mit den Umleitungsoperatoren <& und >& kann er die neuen Kanäle für einzelne Befehle öffnen, zum Beispiel:
# Dateimischer while read X <&3 && read Y <&4 && read Z <&5 do echo $X $Y $Z done 3<Datei-1 4<Datei-2 5<Datei-3Die Anzahl der offenen Kanäle ist durch die Shell oder das Betriebssystem begrenzt. Portable Skripte dürfen nur die Kanäle 0 bis 9 verwenden. Boume-Shell-Benutzer verwenden eine Spezialform des Befehls exec: Stehen hinter dem Befehlswort nur Umleitungen, aber keine Argumente, leitet die Shell die gewünschten Kanäle permanent um. Ist man zum Beispiel an Fehlermeldungen nicht interessiert, kann man sie vernichten mit
exec 2>/dev/nullSoll eine Umleitung später aufgehoben werden, kann man den ursprünglichen Kanal duplizieren:
exec 3<&0 <dateiverbindet beispielsweise die Standardeingabe mit einer Datei,
exec <&3stellt die alte Verbindung wieder her. Der Ordnung halber schließt man mit exec 3<& den zusätzlichen Eingabekanal, wenn man ihn nicht mehr braucht. Analog dazu schließt der Operator x>&- einen Ausgabekanal.
* | Der Stern steht für eine beliebige Zeichenfolge - oder für
überhaupt kein Zeichen. Dazu ein Beispiel: "ab*" steht für alle Dateinamen, die mit "ab" anfangen, auch für "ab" selbst ("ab", "abc", "abcd", "abxyz", usw.). |
? | Das Fragezeichen steht für genau ein beliebiges
Zeichen. Zum Beispiel: "?bc" steht für alle Dateinamen mit 3 Zeichen, die auf "bc" enden ("abc", "bbc", "1bc", "vbc", "xbc", usw.), nicht jedoch für "bc". |
[ ] | Die eckige Klammer wird ersetzt durch eines der in der Klammer stehenden Zeichen. Auch ein Bereich ist möglich, z. B. [a-k] = [abcdefghijk]. Beispiel: "a[bcd]" wird ersetzt durch "ab", "ac" und "ad". Soll das Minuszeichen selbst in die Zeichenmenge aufgenommen werden, muß es an erster Stelle stehen (gleich nach der öffnenden Klammer). |
[! ] | Die eckige Klammer mit Ausrufezeichen wird ersetzt durch eines der nicht in der Klammer stehenden Zeichen, zum Beispiel: "[!abc]" wird ersetzt durch ein beliebiges Zeichen außer a, b oder c. Soll das Ausrufezeichen selbst in die Zeichenmenge aufgenommen werden, muß es an letzter Stelle stehen. |
\ | Der Backslash hebt den Ersetzungsmechanismus für das folgende Zeichen auf. Beispiel: "ab\?cd" wird zu "ab?cd" - das Fragezeichen wird übernommen. Wichtig: Bei der Umleitung von Ein- und Ausgabe werden Metazeichen in den Dateinamen hinter dem Umleitungszeichen nicht ersetzt. |
Beispiele für die Anwendung:
ls -l a*
listet alle Dateien, die mit "a" anfangen
ls test? listet alle Dateien die mit "test" anfangen und 5 Zeichen lang sind ("test1", "test2", "testa")
ls /dev/tty1[1-9] listet alle Terminalbezeichnungen mit einer 1 in der Zehnerstelle ("tty11", "tty12", ... , "tty19")
Lebenswichtig:
Der * ist ein gefährliches Zeichen, Tippfehler könne
zum Fiasko führen, wenn aus Versehen ein Leerzeichen zuviel getippt
wird.
rm a* löscht beispielsweise alle Dateien, die mit "a" anfangen.
rm a * löscht dagegen erst die Datei "a" und dann alle Dateien
im Verzeichnis.
Anmerkungen:
" " | Keine Ersetzung der Metazeichen * ? [ ], jedoch Ersetzung von
Shellvariablen (siehe unten) und Ersetzung durch die Ergebnisse von Kommandos
(Backquote). Auch \ funktioniert weiterhin. Dazu ein Beispiel:
echo Der * wird hier durch alle Dateinamen ersetzt echo "Der * wird hier nicht ersetzt" |
' ' | Das einfache Anführungszeichen unterdrückt jede
Substitution. Zum Beispiel:
echo 'Weder * noch `pwd` werden ersetzt' |
` ` | Zwischen Backquote (Accent Grave) gesetzte Kommandos werden ausgeführt
und das Ergebnis wird dann als Parameter übergeben (d. h. die Ausgabe des Kommandos
landet als Parameter in der Kommandozeile). Dabei werden Zeilenwechsel zu Leerzeichen.
Braucht dieses Kommando Parameter, tritt die normale Parameterersetzung in Kraft.
Zum Beispiel:
echo "Aktuelles Verzeichnis: `pwd`"
Weil die verschiedenen Quotes manchmal schwer zu unterscheiden sind, wurde bei der bash
eine weitere Möglichkeit eingeführt. Statt in Backquotes wird die Kommandofolge
in $( ... ) eingeschlossen., z. B.:
|
Im Verlauf des ersten Aufrufs arbeitet jede Shell zunächst die Datei /etc/profile ab, in der der Systemverwalter für alle Anwender gültige Kommandos und Variablen eintragen kann. Daran anschließend sucht die Bash nach einer der folgenden Dateien im Heimatverzeichnis des Benutzers und führt die jenige aus, die zuerst gefunden wird:
Abhängig von der eingesetzten Terminalemulation können Sie Kombinationen mit der [Esc]-Taste oft auch mit der [Alt]-Taste nachgebilden. Statt also nacheinander [Esc] und [F] zu drücken, funktioniert meist auch die Kombination [Alt]+[F].
Die Anzahl der Befehlszeilen wird mit der Variablen HISTSIZE eingestellt. Wächst die History darüber hinaus, verwirft die Bash die ältesten Zeilen.
alias dir='ls -l' alias cd..='cd ..' alias md='mkdir' alias rd='rmdir' alias del='rm -i'Ohne Parameter gibt dieser Befehl eine Liste der aktuell definierten Aliasnamen aus. Zum Löschen eines Alias-Eintrags verwendet man den Befehl unalias Name.
Auch für die Ausgabe gibt es zwei Möglichkeiten:
![]() |
![]() |