UNIX Shell
Willemers Informatik-Ecke
Die Shell ist der Kommandointerpreter des UNIX-Systems. Da die Shell letztlich eine Anwendung ist, kann man sie leicht austauschen. Je nach persönlichem Geschmack kann sich jeder Anwender seine eigene Shell zuordnen lassen. Welche Shell nach dem Einloggen gestartet wird, steht in der /etc/passwd. Man kann sich eine Shell aber auch jederzeit ohne Zugriff darauf direkt von der Konsole starten.

Einige Fähigkeiten der Shell sind bereits schon besprochen worden. So ist die Auswertung der Wildcards eine Funktionalität der Shell. Auch das Zeichen für die Umleitung von Ein- und Ausgabe, die Pipe und sogar die Reihenfolgebefehle für das Starten der Programme sind eigentlich Dinge, die von der Shell abhängen. Glücklicherweise halten sich die verschiedenen Shells an diesen Stellen an den von der ersten Shell, der Bourneshell vorgegebenen Standard.

Auch die Jobverwaltung für gestoppte Prozesse wurde schon als besondere Fähigkeit der Shell genannt.

Im Bereich Programmierung wird auf die Programmierung mit den Shellbefehlen eingegangen. Dort finden sich Strukturbefehle, die durchaus im Tagesgeschäft sehr hilfreich sein können. Man kann diese Befehle nämlich durchaus auch anwenden, ohne gleich einen Skript schreiben zu müssen. So kann man beispielsweise die Schleife for immer dann gut einsetzen, wenn man mit mehreren Dateien bestimmte Dinge anstellen möchte. Beispiel:

gaston> for i in *.mett
> do
> verwurste $i >$i.neu
> rm $i
> mv $i.neu $i
> echo $i
> done
gaston>

Die Befehlseingabe wird solange nicht beendet, bis das abschließende done nicht genannt ist, obwohl die Returntaste gedrückt wurde. Im Beispiel nimmt die Variable i alle Dateinamen des aktuellen Verzeichnisses nacheinander an, deren Maske auf *.mett passt. Mit dem Programm verwurste wird jede der Dateien nacheinander erst in eine neue Datei umgewandelt. Dann wird das Original gelöscht und schließlich die neu entstandene Datei in den Originalnamen umgenannt. Ein solches Szenario würde sich anbieten, wenn die Dateien derart groß sind, dass eine parallele Bearbeitung vielleicht die Kapazität der Festplatte sprengen würde.

alias

Außer der ersten Bourne Shell kennen alle Shells den Befehl alias. Man kann damit ein neues Kommando, ein so genanntes Alias für komplexere Befehle geben. Einer der einfacheren Umsetzungen ist ll für das oft benötigte ls -l. Dazu wird definiert:

alias ll 'ls -l'

Nun wird jedesmal, wenn ll als Befehl an der Konsole eingetippt wird, diese Zeichenkette durch ls -l ersetzt. Bei vielen Systemen findet man bereits einen solchen alias auf ll oder l vorinstalliert. Es ist durchaus möglich, ll auch Parameter anzuhängen.

Um einen Alias wieder aufzuheben, wird der Befehl unalias verwendet.

Nachdem man mit alias viele neue Befehle definieren kann, möchte man manchmal auch wissen, was der Befehl, den man gerade ausführt, wirklich ist.

gaston> type ll
ll is aliased to `ls -l'

Handelt es sich bei dem Befehl nicht um einen Alias, wird der Pfad der Programmdatei angezeigt. Mit dem Befehl file kann man dann weiter feststellen, ob es sich um einen Skript oder ein compiliertes Programm handelt.

Startupdateien der Shell

Beim Starten einer Shell werden automatisch zu Anfang zwei Dateien ausgeführt. Dabei steht eine dieser Dateien im Verzeichnis /etc und wird vom root für alle Benutzer vorgegeben. Für die C-Shell heißt diese Datei csh.cshrc und für die anderen profile. Diese zentrale Datei gilt für alle Benutzer und sorgt für eine gleiche Startumgebung.

Grenzen setzen

Hier werden Standardvariablen wie PATH vorbesetzt. Hier werden aber auch Begrenzungen eingerichtet, typischerweise mit dem Befehl ulimit. Diese kann man sich als Anwender mit ulimit -a anschauen.

Aus dem Heimatverzeichnis des Anwenders wird ein Shellskript gestartet, der vor allem Einstellungen beinhaltet, die der Benutzer nach eigenem Geschmack einstellen kann. Für die C-Shell ist das die Datei .cshrc und für die anderen Shells .profile

Bourne Shell (sh) und POSIX

Die Bourne Shell ist die erste Shell gewesen und wurde mit sh aufgerufen. Der POSIX-Standard fordert nach POSIX.2, dass jedes konforme Betriebssystem durch den Aufruf von sh eine POSIX-konforme Shell startet. Da POSIX ein Mindeststandard ist, findet man dort manchmal weit über diesen Standard hinaus gehende Shells. Auf jeden Fall hat damit die Bourne Shell beinahe nur noch historische Bedeutung. Da aber die sh nach POSIX immer verfügbar ist, ist es aus Portabilitätsgründen sinnvoll, Shellskripte für diese Shell zu schreiben, wenn sie auf unterschiedlichen UNIX-Rechnern laufen sollen. Es ist aber deswegen nicht notwendig, diese auch als Anwendershell zu benutzen, da der Shellskript die benötigte Shell selbst starten kann.

kompatibel aber unkomfortabel

Die Möglichkeiten der Bourne Shell sind ein wenig eingeschränkt, wenn man sie mit den modernen Shells vergleicht. Insbesondere ihr Komfort beim Editieren der Kommandos könnte man mit dem Begriff archaisch umschreiben. Ein Zurückholen der letzten Kommandos gibt es beispielsweise nicht. Aus diesem Grund ist diese Shell höchstens noch aus Kompatibilitätsgründen vorhanden. Für die normale Arbeit wird man normalerweise eine modernere Shell verwenden. Will man möglichst hohe Kompatibilität, wird man die Kornshell oder die bash verwenden.

Kornshell (ksh)

Die Kornshell ist eine Weiterentwicklung der Bourne Shell mit höherem Komfort. So kennt sie Aliase und die Jobverwaltung mit jobs, bg und fg.

Beim Start werden die Dateien /etc/profile und die Datei .profile aus dem Heimatverzeichnis gestartet.

Namensauflösungen

Beginnt ein Verzeichnis mit einer Tilde (~), so wird diese durch den Pfad des Heimatverzeichnisses ersetzt. Aus ~/test wird die Shell /home/arnold/test auflösen, wenn das Heimatverzeichnis /home/arnold ist.

Durch zweimaliges Tippen der ESC-Taste versucht die Kornshell den Datei- oder Pfadnamen des angefangenen Wortes anhand der erreichbaren Datei- bzw. Verzeichnissnamen zu vervollständigen.

Umleitung der Ausgabe

Das Größerzeichen leitet die Standardausgabe (stdout) auf eine Datei um. Die Umleitung der Standardfehlerausgabe (stderr) erfolgt, indem eine 2 vor das Größerzeichen gesetzt wird. Sollen stdout und stderr in die gleiche Datei umgeleitet werden, wird 2>1 verwendet.

Befehl Wirkung
cc haus.c > out Umleitung der Standardausgabe, Fehler am Terminal
cc haus.c 2> out Umleitung der Fehler, Standardausgabe am Terminal
cc haus.c 2>&1 out Umleitung der Ausgabe und der Fehler nach out

Besonderheiten bei Variablen

export

Der Befehl export dient dazu, Variablen an Nachfolgeprogramme weiter zu geben. Variablen werden für die aktuelle Shell definiert. Wird ein Programm von der Shell aus gestartet, werden die Variablen nicht weitergegeben. Das kann besonders lästig sein, wenn die Variablen eigentlich das Verhalten des gestarteten Programms ändern sollen. Damit die Variable und ihre Inhalte an alle Kindprozesse weitergegeben werden, muss die Variable exportiert werden. Als Beispiel dient ein Programm, das über die Variable DATA den Pfad und Dateinamen seiner Daten übermittelt bekommt.

gaston> DATA=/home/arnold/my/database
gaston> export DATA
gaston> auswertung

let lässt rechnen

Die Kornshell kann mathematische Ausdrücke berechnen und in Variablen ablegen. Dazu stellt man den Befehl let einer Variablenzuweisung voran. Als Operanden können +, -, *, / und % (als Modulo) verwendet werden. Auch Klammern werden korrekt interpretiert. Es darf allerdings kein Leerzeichen in dem Ausdruck stehen. Besonders praktisch ist die Fähigkeit, mit verschiedenen Zahlensystemen zu arbeiten. Dazu wird einer Zahl die Basis gefolgt von einem Hashzeichen (#) vorangestellt. Die Dualzahl 2#11 entspricht einer dezimalen 3 und um die Hexadezimalzahl 1a darzustellen, wird 16#1a oder 16#1A verwendet. Beispiel:

gaston> let wert=45+5
gaston> echo $wert
50
gaston> wert=45+5
gaston> echo $wert
45+5
gaston> let wert=16%5
gaston> echo $wert
1
gaston> let wert=(1+3)*2
gaston> echo $wert
8
gaston> let wert=16#1a
gaston> echo $wert
26
gaston>

Im Beispiel ist zu sehen, dass ohne die Verwendung von let die Variable den Ausdruck als Text übernimmt. Die Kornshell kennt auch Modulorechnung und Klammern. In den letzten beiden Beispielen wird die Umrechnung von hexadezimalen Werten demonstriert.

History

History mit fc

Die Kornshell merkt sich standardmäßig die letzten 128 Kommandos in der Datei .sh_history des Heimatverzeichnisses. Die Bearbeitung der Kommandos erfolgt mit dem Befehl fc. Ohne weitere Parameter aufgerufen, startet fc den Systemeditor (meist vi). Darin findet sich das zuletzt eingegebene Kommando. Im Editor kann man das Kommando verändern und speichern. Dadurch wird die geänderte Version ausgeführt.

Wird als Argument von fc eine Zeichenkette gegeben, wird der letzte Befehl in den Editor geladen, der mit dieser Zeichenkette beginnt. Mit der Option -e kann ein Kommando direkt verändert werden, ohne den Editor zu belästigen. Wieder kann mit dem Argument nach der letzten Zeile gesucht werden, die mit dieser Zeichenkette beginnt. Mit einer Zuweisung kann ein Teilstring dieses Kommandos ersetzt werden. In der Praxis sieht das so aus:

gaston> let wert=16#1A
gaston> echo $wert
26
gaston> fc -e -
echo $wert
26
gaston> fc -e - 1A=22 let
let wert=16#22
gaston>

Im letzten fc wird das letzte Kommando gesucht, dass mit >>let<< beginnt und innerhalb des Kommandos die Zeichenkette 1A durch 22 ersetzt.

Mit Erleichterung wird der geneigte Leser zur Kenntnis nehmen, dass er statt mit fc zu arbeiten, die Editierkommandos des vi auf die Kommandoebene holen kann. Der folgende Befehl schaltet dies ein.

set -o vi

Kommandos editieren wie im vi

Danach schaltet die ESC-Taste in den Editiermodus um. Man kann nun mit + und - die vergangenen Zeilen wieder heranziehen, bis man zu dem Befehl gelangt, den man ausführen möchte. Man kann sogar mit dem Schrägstrich in den bisherigen Kommandos suchen. Hat man den gewünschten Befehl gefunden, kann man ihn noch modifizieren. Innerhalb der Zeile kann man mit i einfügen und mit d löschen. Das Bewegen innerhalb der Zeile funktioniert mit der Leertaste und dem Backspace, aber auch wortweise mit w und b. Wer mit dem vi umgehen kann, wird sich wohlfühlen.

set -o emacs

Kommandos editieren wie im emacs

Die Benutzer des emacs werden sich schon gedacht haben, dass man auch dessen Kommandos zur Bearbeitung der History verwenden kann. Wichtig sind vor allem die folgenden Befehle:

Taste Funktion
ctrl-P zeilenweises Rückwärtsblättern der Kommandos
ctrl-N zeilenweises Vorwärtsblättern der Kommandos
ctrl-B mit dem Cursor nach links
ctrl-F mit dem Cursor nach rechts
ctrl-A An den Anfang der Zeile
ctrl-E An das Ende der Zeile
ctrl-D löscht das Zeichen unter dem Cursor
ctrl-K lösche bis an das Ende der Zeile
ctrl-R inkrementelles Suchen

C-Shell (csh)

Die C-Shell war vor allem für Programmierer entwickelt worden. Ihre Skriptsprache unterscheidet sich erheblich von anderen Shells und ähnelt der Sprache C. Die Leistungsfähigkeit der Skriptsprache ist heutzutage nicht mehr so relevant, da man Perl oder Tcl/Tk heranzieht, wenn man eine leistungsstärkere Skriptsprache als die der Shell benötigt. Unabhängig davon ist die C-Shell modern und hat ihre Freunde. So findet sie sich auch auf MacOS X als Standardshell.

Die Startdatei der C-Shell heißt .cshrc. Statt der Datei .profile wird bei einer Login Shell die Datei .login gestartet. Neu gegenüber der Bourne Shell ist, dass es auch eine Datei gibt, die beim Ausloggen gestartet wird. Sie heißt konsequenterweise .logout.

Umgebungsvariablen werden mit dem Befehl setenv gesetzt.

setenv VARIABLE  wert

Durch ESC versucht die C-Shell den angefangenen Dateinamen anhand der im Verzeichnis existierenden Dateinamen automatisch zu vervollständigen.

Umleitung

Beim Umleiten des Fehlerausgabekanals (stderr) in eine Datei muss bei der C-Shell auch der normale Ausgabekanal (stdout) in diese Datei umgeleitet werden. Das Zeichen für die gemeinsame Umleitung ist eine Kombination aus Größerzeichen und kaufmännischem Und (>).

cc -o moin moin.c >
outerr

Dieser Mechanismus gilt ebenso bei einer Pipe. Wird dem senkrechten Strich ein angehängt, geht auch stderr durch die Pipe. Anders ausgedrückt geht die stderr bei der C-Shell entweder auf den Bildschirm oder folgt der stdout durch Angabe des kaufmännischen Und () hinter dem Umleitungszeichen.

History

Die C-Shell verwendet das Ausrufezeichen als Historyzeichen. Daneben werden auf den neueren Systemen normalerweise die Cursortasten unterstützt.

Zeichen bewirkt...
!! ruft die letzte Zeile noch einmal auf
!5 ruft die fünftletzte Zeile noch einmal auf
!abc ruft die letzte Zeile auf, die mit abc beginnt
!?abc ruft die letzte Zeile auf, die abc enthält
!$ verwendet das Argument der letzten Zeile an dieser Stelle
Teile des letzten Kommandos können ersetzt werden. Dazu folgendes Beispiel:

hpsrv 2: lx hel*
lx: Command not found.
hpsrv 3: ^lx^ls
ls hel*
hello.cpp
hpsrv 4:

Das fehlerhafte lx wird durch das korrekte ls ausgetauscht. Nach Return wird der korrigierte Befehl gestartet. Im folgenden Beispiel wird noch einmal der Befehl geholt, der mit ls beginnt. Im Anschluss wird das Argument des letzten Kommandos im neuen Kommando wieder verwendet.

hpsrv 4: !ls
ls hel*
hello.cpp
hpsrv 5: echo !$
echo hel*
hello.cpp
hpsrv 6:

Promptgestaltung

Statt der Umgebungsvariablen PS1 für den Prompt verwendet die C Shell die Variable prompt, die mit set gesetzt wird.

set prompt="%\!:"

Dieser Befehl führt dazu, dass vor jedem Kommando eine Nummer steht, auf die man sich in der History beziehen kann.

Bourne Again Shell (bash)

bash ist die Abkürzung für bourne again shell. In ihrer Kommandostruktur setzt sie also auf der alten Bourne Shell auf, fügt ihr aber diverse Fähigkeiten hinzu, die man auch in anderen Shells wie beispielsweise der Kornshell (ksh) oder der C-Shell (csh) findet.

bash ist Standard unter Linux

Die bash ist die Standardshell der Linux-Systeme, findet sich aber auch auf anderen UNIX-Derivaten, selbst für OS/2 oder MS-Windows kann man die bash bekommen. Unter Linux gibt es keine sh mehr. Der Standardeintrag /bin/sh ist ein Link auf die bash. Da die bash eine Obermenge der sh ist, ist eine separate Bourne Shell auch nicht erforderlich.

Ablauf der Startdateien

Nachdem die /etc/profile abgearbeitet wurde, wird die .profile im Heimatverzeichnis gestartet. Innerhalb der .profile wird die Ausführung der .bashrc gestartet, sofern sie vorhanden ist. Am Ende der .bashrc wird die Datei .alias gestartet, in der typischerweise die alias Definitionen gesammelt werden.

History

Normalerweise ist die bash so installiert, dass mit den Pfeiltasten durch die bisherigen Kommandos navigiert werden kann. Wenn es um mächtigere Kommandos geht, werden die ctrl-Tasten des emacs verwendet. Wie bei der Kornshell kann man mit set -o vi die Tastenkombinationen des vi aktivieren. Zu guter Letzt finden auch Freunde der C-Shell ihre Historyfunktionen mit dem Ausrufezeichen implementiert.

Funktionstasten

Mit den Pfeiltasten kann man die Befehle vor und rückwärts blättern. Mit den Links- und Rechtspfeiltasten kann man innerhalb des Befehls positionieren. Ctrl-A bewegt den Cursor an den Anfang der Zeile, ctrl-E bringt ihn zum Ende. Backspace funktioniert wie erwartet. Das Löschen des Zeichens unter dem Cursor erfolgt mit ctrl-D oder der Taste Delete. Die inkrementelle Suche funktioniert wie beim emacs Bei jedem Tastendruck wird in der History nach einem passenden Befehl gesucht. Dabei schlägt bash immer den nächsten passenden Befehl vor.

gaston> 
(reverse-i-search)`ps': ps -axwww

Taste Funktion
ctrl-A An den Anfang der Zeile
ctrl-E An das Ende der Zeile
ctrl-D löscht das Zeichen unter dem Cursor
ctrl-K lösche bis an das Ende der Zeile
ctrl-R inkrementelles Suchen

Dateinamenergänzung

Wenn ein Dateiname mit den ersten Buchstaben eingegeben ist, kann man ihn mit der TAB-Taste vervollständigen, wenn er eindeutig ist. Ist der Name nicht eindeutig oder exitiert kein Dateiname mit diesen Zeichen, piept es. Durch nochmaliges Tippen von TAB wird die Liste aller passenden Namen angezeigt.

Die Ergänzung funktioniert nicht nur bei den Parametern. Auch beim Aufruf eines Befehls können die ersten Zeichen eingegeben werden und mit der Tabtaste vervollständigt werden. Dabei werden alle ausführbaren Dateien angeboten, die über den Pfad der Variable PATH erreichbar sind.

Best of...

Wie schon erwähnt, wurde in der bash alles realisiert, was in anderen Shells bemerkenswert ist. Das beginnt bei der Kornshell mit dem Befehl fc bis zur Auswertung arithmetischer Ausdrücke mittels let. Die Liebhaber der C-Shell finden ihre Ausrufezeichen wieder. Das ist wohl der Grund, warum die bash inzwischen sehr weit verbreitet ist.

Diese Seite basiert auf Inhalten aus dem Buch Arnold Willemer: Wie werde ich UNIX-Guru?