Aus LinuxUser 06/2000

Shell-Tipps

(Un)geliebte Shell

Alte (Unix-) Hasen lieben sie, Linux-Ein- und Aufsteiger stehen ihr oft mindestens skeptisch bis ablehnend gegenüber: der Shell. Wie eine Muschelschale legt sie sich um die Perle (den Linux-Kernel) und regelt alle Kommunikation mit ihm. Dieses für viele unbekannte Wesen wollen wir in unserer neuen Reihe näher beleuchten und versuchen, Vorurteile abzubauen, sowie Ihnen einen Einblick in die Möglichkeiten dieser mächtigen Anwenderschnittstelle geben. fortgeschrittenere Shell-User seien an dieser Stelle aufgefordert, ihre Tipps und Tricks an uns zu schicken, so dass wir sie in dieser Serie weiter verbreiten können.

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.

Abbildung 1: Vom Shellstart zum User-Prozess
Abbildung 1: Vom Shellstart zum User-Prozess

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.

Mal eine andere Shell

Anwender können die ihnen beim Systemstart zur Verfügung stehende Login-Shell jederzeit wechseln. So genügt es, eine andere Shell zu starten, um mit dieser arbeiten zu können:

$>  echo  $BASH_VERSION
2.03.0(1)-release
$>  zsh
$>  echo  $BASH_VERSION

Hier wird die Shell durch die Variable $BASH_VERSION identifiziert, die – natürlich nur bei einer Bash – den Versions-String der aktuellen Shell enthält. Verlassen wird diese Shell durch den Befehl exit.

Dauerhaft kann der Anwender seine Login-Shell mit dem Befehl chsh (change shell) ändern:

$>  chsh
Password:
Changing the login shell for LinuxUser
Enter the new value, or press return for the default
            Login  Shell  [/bin/bash]:

Distributions- und systemabhängig wird zunächst nach dem Passwort des Anwenders gefragt, bevor er eine neue Shell (mit dem gesamten Pfad!, also zuvor ausprobieren) angibt. In der Datei /etc/login.defs wird durch das Schlüsselwort „CHFN_AUTH“ festgelegt, ob vor dem Wechsel der Login-Shell nach dem Passwort gefragt wird. Anwender haben Zugriff auf alle Shells, die in der Datei /etc/shells aufgeführt sind. Dabei können auch sogenannte eingeschränkte (restricted) Shells in dieser Liste aufgeführt sein. Bei einer „restricted shell“ sind einige Möglichkeiten, die normalerweise zur Verfügung stehen, aus Sicherheitsgründen deaktiviert. So ist in der Regel kein Verzeichniswechsel mehr möglich, auch können Programme nicht mehr durch die Eingabe eines absoluten Pfades gestartet werden. Weitere Einschränkungen hängen von der Shell ab. Außerdem können restricted Shells nicht mehr verlassen werden. Die Bash agiert als „restricted Bash“, wenn sie mit der Option -r aufgerufen wird.

Blick zurück, nach vorn

Die erste Shell unter Unix wurde nach ihrem Entwickler Bourne benannt. Sie ist heute als Standard-Shell unter dem Namen sh auf nahezu allen Systemen verfügbar oder wird von anderen Shells emuliert. Die ursprüngliche Bourne-Shell war nicht sehr komfortabel und verfügte nur über einen Bruchteil der Features moderner Shells. Von der Bedienung entsprach sie etwa dem COMMAND.COM-Interpreter unter DOS. Kein Wunder also, dass es bald mehrere Projekte gab, die versuchten, „bessere“ Shells zu entwickeln. Als sehr anwenderfreundlich hat sich die ksh (Korn Shell) herausgestellt; eine freie Variante dieser Shell ist unter Linux mit dem Namen pdksh (oder ksh) verfügbar. Eine besonders für Programmierer interessante Shell ist die C-Shell; sie verfügt über eine an die Konventionen dieser Programmiersprache angepasste Syntax. Heute wird überwiegend die Weiterentwicklung der klassischen C-Shell eingesetzt, die unter dem Namen tcsh auf vielen Systemen installiert ist. Unter Linux hat sich dagegen eine andere Shell durchgesetzt: die Bourne Again SHell, kurz „Bash“, Programmname bash. Sie vereinigt viele Features der Korn- und der C-Shell, steht unter der GPL und ist auf vielen Rechnern (und nicht nur unter Linux) verfügbar. Ihre Entwickler Brian Fox und Chet Ramey pflegen dieses inzwischen sehr umfangreiche Programm seit vielen Jahren, momentan ist die Version 2.0.5 aktuell. Ein anderer Artikel in diesem Heft geht auf diese Shell näher ein.

Viele neue Shells sind in den letzten Jahren entstanden. Sie sind alle mehr oder weniger kompatibel zur ursprünglichen Bourne Shell. Die Bash emuliert beispielsweise eine Bourne Shell, wenn sie unter dem Programmnamen sh gestartet wurde. (Aber Achtung: Nicht alle Erweiterungen der Bash werden in diesem Modus wirklich deaktiviert, so dass das Verhalten dieser Shell von dem einer echten Bourne Shell abweichen kann.) Eine der leistungsfähigsten Shells, die heute in vielen Linux-Distributionen enthalten ist, ist übrigens die Z-Shell (zsh) von Paul Falstad. Inzwischen wurden auch eine Reihe von „interaktiven“ Shells entwickelt, die – ähnlich dem unter DOS bekannten „Norten Commander“ – für einfache Aufgaben bei der Manipulation von Dateien eingesetzt werden können.

Abbildung 2: Der Midnight Commander stellt eine "interaktive" Shell dar.
Abbildung 2: Der Midnight Commander stellt eine „interaktive“ Shell dar.

Shells im Überblick

Shell Name und Eigenschaften
sh Bourne-Shell: das Original wird unter Linux nur durch einen Link realisiert
ash (Almquist Shell) ist ein einfacher Bourne-Shell Clone, der über keine Editierfunktionen für die Befehlszeile verfügt, wenig zusätzliche Features
sash Diese statisch gelinkte Shell enthält eine Reihe von eingebauten Befehlen: chgrp, chmod, chown, cmp, cp, dd, echo, ed, grep, gunzip, gzip, kill, ln, ls, mkdir, mknod, more, mount, mv, printenv, pwd, rm, rmdir, sync, tar, touch, umount, where
rsh restricted“ Bourne-Shell, diese eingeschränkte Shell wird als Link auf die Bash realisiert und bietet dem Anwender nur begrenzte Möglichkeiten
csh C-Shell: die Berkeley-Version der sh. Erweiterte Funktionen, eine Befehlszeilenhistory und gute Programmierumgebung im C-Stil, aber keine Editierfunktionen für die Befehlszeile
tcsh Tenex-C-Shell (erweiterte C-Shell): die heute unter Linux verwendete Variante der Csh, mit Editierfunktionen für die Befehlszeile
ksh Korn-Shell: diese komfortable Shell wird unter Linux als Link auf pdksh realisiert. Kompatibel zur sh, mit guten Editierfunktionen für die Befehlszeile und Jobmanagement
rksh „restricted“ Korn-Shell: eingeschränkte Version der K-Shell
bash Bourne-Again Shell: Standard-Shell unter Linux, vereinigt die Funktionen der K-Shell, C-Shell und weitere.
zsh Z-Shell: Eine moderne und komfortable Shell, kompatibel zur sh, mit wesentlich erweiterten Funktionen
git GNU Interactive Tool
mc Midnight Commander
fr File Runner
tkdesk NeXT-ähnlicher Datei-Manager
tkworld Versuch einer „grafischen Shell“
uc Unix Commander, grafische Shell

Fazit

Wie Sie gesehen haben, stellen Shells eine sehr universelle Möglichkeit zur Arbeit mit dem System dar. Nach einigen Erfahrungen werden Sie schnell merken, dass Sie beim Einsatz einer Shell eine Menge Arbeit sparen können und Ihnen dabei noch wesentlich mehr Möglichkeiten zur Verfügung stehen, als wenn Sie sich nur auf die grafischen Tools beschränken. Nicht „Desktop oder Shell“ ist die Devise sondern „Desktop und Shell“. Damit Ihnen der Umgang mit der Bash leichter fällt, werden deren Editierfunktionen im folgenden Artikel genauer beschrieben.

Glossar

Environment
Eine Anzahl von (Environment-) Variablen, deren Inhalt dem Prozess Informationen über die Umgebung geben, in der sich die Ausführung abspielt. So ist im Environment der Typ der Shell gespeichert, die den Prozess gestartet hat, das Terminal mit dem er verbunden ist und vieles mehr. Das Environment kann mit dem Befehl printenv angezeigt werden, env modifiziert es. Einzelne Variablen können mit den Shell-Befehlen (declare oder export auf der Bash oder setenv bei der C-Shell) eingestellt werden.
Prozess
Ein gerade laufendes Programm wird unter Linux als „Prozess“ bezeichnet. Zu einem Prozess gehören neben der ausführbaren Datei noch weitere Informationen: das Environment, Daten über den Prozess selbst und über den Prozess, von dem er abstammt. Prozesse werden über die ihnen zugeordnete Prozessidentifikationsnummer (PID) identifiziert, nicht etwa über den Programmnamen. Programme sind unter Linux einfach ausführbare Dateien, also binäre (compilierte) Programm oder interpretierte Skripte. Die Ausführbarkeit einer Datei wird anhand des „x“-Bits bei den Dateiattributen festgestellt und festgelegt.
Muster
Ein Muster (oder englisch: Pattern) ist ein Dateiname, der Joker-Zeichen wie z. B. die auch von DOS bekannten Wildcards „*“ und „ß“ enthält. Unix-Systeme kennen noch zusätzliche Möglichkeiten für die Auswahl mehrerer Dateien, etwa file[123] für file1, file2 und file3.
Debug
Unter „Debuggen“ versteht man die Suche nach und Behebung von Programmfehlern. Die Wortwahl (Debugging: Entwanzung) kommt aus der Zeit, als die ersten Rechner noch röhrenbasiert waren: Dort gab es dann Angestellte, die die Computer-Anlagen nach Käfern und anderen Kleintieren durchsuchen mussten, welche Kurzschlüsse verursachen konnten.
Skript
Ein (Shell-) Skript ist in etwa mit einer Batch-Datei von DOS vergleichbar: hier stehen in einer lesbaren Datei mehrere Shell-Befehle hintereinander, die in der angegebenen Reihenfolge ausgeführt werden. Mit Tests kann die Ausführung eines solchen Skripts auch verzweigen, so dass sich ähnliche Programmiermöglichkeiten wie bei einer richtigen Programmiersprache ergeben.
LinuxUser 06/2000 KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS
Deutschland

Hinterlasse einen Kommentar

  E-Mail Benachrichtigung  
Benachrichtige mich zu: