Ein Überblick
Was sind eigentlich Shells? Was leisten sie? Wer setzt sie wofür ein? Welche grundlegenden Konzepte liegen ihnen zugrunde? Diese und weitere Fragen soll dieser Artikel klären - zunächst aber ein kleiner historischer Überblick.
Als die ersten Unix-Systeme entwickelt wurden, erfolgte die Programmierung von Computern noch überwiegend über Lochstreifen oder Karten. Diese umständliche Methode wurde nach und nach durch Terminals ersetzt, mit denen die Maschinenbefehle mehr oder weniger direkt in den Hauptspeicher des Rechners geschrieben werden konnten. Um dieses Verfahren zu vereinfachen und vor allem um es sicherer zu machen, entwickelten die Programmierer zwei grundlegende Werkzeuge: die Shell und den Editor. Während der Editor zur Eingabe von Daten verwendet wird, steuert die Shell den Programmablauf. Dieses Konzept findet sich bis heute nahezu unverändert in allen Betriebssystemen wieder. Auch grafische Oberflächen "verstecken" diese Konzeption nur.
Unter Linux (und allen Unix-artigen Betriebssystemen) kann der Anwender nur über eine Shell mit dem System kommunizieren. Bei der Anmeldung am System ("Login") startet das getty-Programm den login-Befehl, der die Anmeldung des Anwenders durchführt, also seinen Login-Namen und das Passwort anhand der Passwortdatei /etc/passwd überprüft und ihm anschließend den Zugang zum System mit einer Shell ermöglicht. (Die Beschreibung gilt für die Anmeldung an einer Konsole; bei grafischer Anmeldung sieht es anders aus.) Diese erste Shell wird daher als "Login-Shell" bezeichnet. Sie unterscheidet sich in einigen Punkten von anderen Shells, die ein Anwender startet: Beim Start der Login-Shell werden oft zusätzliche (oder manchmal ganz andere) Start-Dateien ausgeführt als beim Start einer "normalen" Shell. Der Grund ist einfach: Beim Login müssen noch grundlegende Einstellungen für den Account des Users eingestellt werden, die später nicht mehr erforderlich sind. So können hier beispielsweise Limits definiert werden, die verhindern, dass die Programme eines Anwenders über die Maße viel Ressourcen verbrauchen und so die Funktionsfähigkeit des gesamten Systems beeinträchtigen. Oder es werden einige ganz grundsätzliche Einstellungen vorgenommen, die bestimmte Aspekte des Systems widerspiegeln, etwa die Systemarchitektur (wie sie der Befehl arch bekannt gibt), der Name des Systems (wie er mittels hostname ermittelt wird) usw. Diese Informationen werden in dem Environmentder Shell gespeichert und beim Aufruf von Programmen an deren Umgebung weiter vererbt.
Features moderner Shells
Moderne Shells bieten dem Anwender zweierlei: zum einen stellen sie eine komfortable Schnittstelle zum System dar, ermöglichen beispielsweise den Start von Programmen, die Verwaltung von Systemressourcen und ähnliches. Andererseits bilden sie eine einfache aber durchaus leistungsfähige Programmierumgebung. Heutige Shells zeichnen sich durch eine Vielzahl von speziellen Merkmalen aus, die dem Anwender Arbeit abnehmen bzw. ihm bestimmte Arbeitstechniken erst ermöglichen. Ein Beispiel erklärt das Verfahren: Ein Anwender startet ein Programm und bemerkt, dass er für dessen Einsatz noch einige Vorarbeiten hätte erledigen müssen, z. B. eine CD mounten. In diesem Fall kann er durch das mit [Strg+Z] erzeugte "Suspend-Signal" (supendieren: zeitweilig anhalten) den gerade gestarteten Prozess anhalten. Er erhält darauf ein freies Terminal und kann nun alle fälligen Arbeiten durchführen ohne das zuvor gestartete Programm beenden und später erneut starten zu müssen. Dieses als "Job Management" bezeichnete Feature geht aber noch weiter. Mit dem Befehl bg (background) aktiviert er den angehaltenen Prozess im Hintergrund. Dadurch bleibt das Terminal für weitere Aufgaben frei, um z. B. die Resultate des Programms beobachten zu können. Ausgaben eines im Hintergrund laufenden Programms (beispielsweise Fehlermeldungen) werden aber dennoch angezeigt.
Ein zweites Beispiel: Prozesse werden normalerweise beendet, wenn sich ein User ausloggt. Bei lange andauernden Berechnungen (Rendern mit Povray oder ähnliches) muss der Anwender also die ganze Zeit seinen Account überwachen, wenn er nicht mit der Shell eine Übereinkunft getroffen hat, die es ihm ermöglicht, sich auszuloggen und den gestarteten Prozessweiterlaufen zu lassen. Dafür wird gewöhnlich der nohup-Befehl ("no hang up": sende kein Signal zum Beenden) eingesetzt. Die Bash bietet hierfür sogar noch weitere Möglichkeiten.
Eines der wichtigsten Features einer Shell sind die diversen Möglichkeiten, mit Mustern (Patterns) umzugehen. Während es in Datei-Managern nur sehr begrenzte Möglichkeiten gibt, eine Gruppe von Dateien für eine Aktion auszuwählen (sofern man sie nicht "zu Fuß" auswählen will), hat die Shell hier besondere Funktionen anzubieten. Befehle und Dateinamen lassen sich beispielsweise bei den meisten Shells mittels der Tabulatortaste komplettieren:
$> kj[tab]ukebox
Die Tabulatortaste ergänzt immer so viel von einem Namen, wie eindeutig ermittelt werden kann. Wenn damit ein eindeutiges Ergebnis - also ein eindeutiger Befehls- oder Dateiname - erzeugt wird, fügt die Shell ihn in die Befehlszeile ein. Bleiben mehrere Möglichkeiten zur Auswahl, dann erzeugt die Shell einen Signalton und ergänzt alle Zeichen bis zum ersten Unterschied. Bei einem erneuten "Tab" werden dann die verbliebenen Möglichkeiten angezeigt. (Dies Verhalten lässt sich bei den meisten Shells einstellen.)
Interessant ist in diesem Zusammenhang, dass die meisten Shells über sehr ausgefeilte Mechanismen verfügen, mit denen sie abhängig von der aktuellen Position in der Befehlszeile unterscheiden, welche Form der Komplettierung vorgenommen wird. Das erste Wort in einer Befehlszeile wird immer als Befehlsname komplettiert, es sei denn, eine Pfadangabe wird gerade konstruiert. Für weitere Worte in der Befehlszeile unterscheidet sich das Verhalten verschiedener Shells. Die Bash konstruiert voreingestellt Dateinamen oder Pfade, kann aber auch Variablen-, Host- oder Usernamen komplettieren.
Die meisten Shells stellen noch eine Reihe weiterer Features zur Verfügung: So können für bestimmte, oft verwendete Befehle Abkürzungen (als Alias oder Funktion) definiert werden. Weiterhin bieten die Shells unterschiedlich komfortable Debug-Möglichkeiten. Die Bash erlaubt beispielsweise, alle Schritte eines Skripts einzeln bei der Abarbeitung anzuzeigen. Interessant sind in diesem Zusammenhang auch die (Fehler-) Meldungen, die von vielen Programmen beim Start ausgegeben werden und die oft über Ursachen bei Fehlern informieren. Es ist also immer eine gute Idee, ein neues Programm zunächst von der Shell aus zu starten, bevor es in ein Applikationsmenü aufgenommen wird. Zur Behebung ernsthafter Probleme stellt Linux dem Systemadministrator viele Spezial-Tools zur Verfügung. Am bekanntesten sind strace zum Verfolgen von Kernel-Funktionsaufrufen und ltrace, mit dem Library-Funktionsaufrufe protokolliert werden.



