Die C-Shell und Tcsh |
Übersicht |
Verbreitung erfuhr die C-Shell vor allem durch ihre enge Bündelung mit den BSD-Unix-Systemen. In ihre Entwicklung flossen all die nützlichen Dinge der Bourne Shell ein, garniert mit einigen neuen Eigenschaften. Herausragend war sicher die Verwendung einer History. Die C-Shell erbte von der Bourne Shell zwar das Konzept, die Realisierung orientierte sich jedoch an der Programmiersprache C. Daher auch ihr Name.
Im interaktiven Umgang ist von der Nähe zur Programmiersprache C nichts zu merken. Erst der Shellprogrammierer wird mit der Syntax konfrontiert, die vor allem dem Programmierer entgegen kommen wird.
Im Vergleich zur Bourne Shell agiert die C-Shell recht schwerfällig. Auf heutigen Megahertz-Boliden mag das kein Kriterium Für oder Wider einer Shell zu sein, aber in den Anfängen von Linux verfügten die Rechner über weitaus weniger Leistung. Vielleicht ist hier ein Grund für die geringe Akzeptanz der (Tenex-)C-Shell unter Linux zu suchen.
Während die C-Shell einem kommerziellen Lizenzmodell unterliegt, ist die Weiterentwicklung in Form der Tenex-C-Shell (Tcsh) frei und damit unter Linux verfügbar. Im Wesentlichen unterscheidet sich die Tcsh von ihrem Ahnen durch die verschiedenen Mechanismen zur Vervollständigung nach so genanntem Tenex-Stil.
Aber nicht nur dem C-Programmierer kommt die C-Shell entgegen. Auch wer in der Solaris-Ecke heimisch ist und nur hin und wieder mit Linux in Berührung kommt, muss die vertraute Shell nicht missen.
Nur kurz sollen die wesentlichen Unterschiede zwischen den beiden Shells aufgezählt werden. Die Tenex-C-Shell erweitert die Fähigkeiten der C-Shell um:
Nur das Unterbinden des Einlesens von Benutzer definierten Startdateien wurde in der Tcsh im Unterschied zur C-Shell nicht implementiert.
Und zahlreiche Fehler, die die Implementierungen der C-Shell in sich bergen, sind in der Tcsh ausgemerzt. Leider noch nicht alle, wobei Kenner das für unmöglich halten, da Designfehler manche Ungereimtheiten bedingen.
Fähigkeiten der Tcsh und Definitionen |
In obigem Vergleich zwischen Csh und Tcsh finden Sie die wichtigsten Argumente für die Verwendung der Tcsh. Etwas präziser soll die folgende Aufzählung ihre Stärken untermauern:
Die folgenden Begriffe werden im Laufe des Textes wiederholt benötigt. Ihre Definitionen sind sicher nicht vollständig, sollten aber zum Verstehen ihrer Bedeutung genügen.
Kommentare
Kommando-Trennzeichen
Operatoren
Whitespace
Wort
Start der Tcsh |
Abbildung 1: Unterteilung der Tcsh
Ist die Tenex-C-Shell mit der Standardein- und Standardausgabe (sprich »mit einer (virtuellen) Konsole«) verbunden, so handelt es sich um eine interaktive Shell. Die interaktive Bash teilt sich wiederum ein in die Login Tcsh und die Nicht-Login Tcsh. Eine Shell mit eingeschränkten Nutzungsbefugnissen wie in der Bash gibt es nicht.
Die Tcsh fungiert als Login-Shell, wenn sie entweder explizit mit der Option »-l« ([kleines »L«] und keiner weiteren Option!) gestartet wurde oder wenn das erste Argument (Argument 0) »-« ist.
Die Login-Shell führt zunächst Kommandos aus den System weiten Dateien »/etc/csh.cshrc« und »/etc/csh.login« aus. Die Reihenfolge der Betrachtung der Nutzer definierten Startdateien ist abhängig von der konkreten Version. Meist wird die Datei »~/.tcshrc« betrachtet und nur falls diese nicht existiert die Datei »~/.cshrc«. Falls vorhanden, werden der Reihe die Dateien »~/.history«, »~/.login« und »~/.cshdirs« eingelesen.
Jede Nicht-Login-Shell führt nur Kommandos der Dateien »/etc/csh.cshrc« und »~/.tcshrc« bzw. »~/.cshrc« aus.
Wir beschränken uns hier auf die wichtigsten Optionen.
-c Kommando
Die Tcsh führt das angegebene Kommando aus und endet anschließend. Das Kommando muss ein einzelnes Argument sein; umfasst es Optionen, ist der gesamte Ausdruck zu quoten:
user@sonne> tcsh -c 'ls -l ~/../' insgesamt 8 drwxr-xr-x22 user users 4096 Aug 22 11:12 user drwxr-xr-x 22 tux users 4096 Aug 22 11:12 tux |
-d
-e
-f
-i
-l
-n
-v
-x
-V
-X
In den meisten Konfigurationen, die die Distributoren ausliefern, dürfte die Bash als Login-Shell voreingestellt sein. Bemühen Sie das Kommando chsh, um die Tcsh in der Passwortdatei als Default-Shell einzutragen.
Dies funktioniert jedoch nur, wenn die Tcsh in der Datei /etc/shells eingetragen ist. Ist dem nicht so, könnte Ihnen entweder der Administrator aus der Patsche helfen, indem er den Eintrag in obiger Datei ergänzt oder Sie bauen in einem der Startup-Skripte Ihrer bisherigen Login-Shell den Aufruf »exec /usr/bin/tcsh -l« ein.
Beenden der Tcsh |
Zum Beenden stehen mehrere Möglichkeiten zur Verfügung. Ein [Ctrl]-[D] auf einer leeren Eingabezeile beendet sowohl die Login- als auch die Nicht-Login-Shell. Die Kommandos »logout« und »login« stehen allerdings nur in einer Login-Shell zur Verfügung. Letzteres ersetzt den Shellprozess durch das gleichnamige Kommando.
Eine Besonderheit der Tcsh ist der Autologout-Mechanismus, der über die Belegung der Shellvariable autologout gesteuert wird. Mit dieser können Sie zwei verschiedene Zeiten (in Minuten) definieren. Zum einen die Zeitspanne, nach der die Shell bei Inaktivität automatisch abgemeldet wird und zum anderen (optional) die Dauer der Inaktivität, nach dem die Shell automatisch gesperrt wird. Eine gesperrte Shell kann nur durch Eingabe des Passworts reaktiviert werden. Fünfmalige falsche Passworteingabe führt automatisch zu einem Autologout.
user@sonne> tcsh -l sonne /home/user> set autologout = 1 # Nach 1 Minute des Nichtstuns... user@sonne> auto-logout |
Beim Beenden der Tcsh setzt diese in Abhängigkeit vom verwendeten Mechanismus die »logout« Shellvariable auf »normal« oder »automatic«. Abschließend führt sie Kommandos aus den Dateien »/etc/csh.logout« und »~/.logout« aus.
Syntax der Tcsh |
Der weitere Text erklärt:
Normalerweise leitet das Doppelkreuz # in der Tcsh einen Kommentar ein. Alles, was diesem Zeichen folgt, wird von der Tcsh ignoriert bis zum nächsten Zeilenumbruch. Dies gilt sowohl für die interaktive als auch für die nicht-interaktive Tcsh.
Eine Ausnahme sind Shellskripte, in denen die erste Zeile mit #!... beginnt. Für die Tcsh ist es die Anweisung, die nachfolgenden Zeilen mit dem hinter »#!« angegebenen Interpreter (eine Shell, Perl, awk, ...) auszuführen.
Die Bedeutung von # kann durch Quoten (siehe später) aufgehoben werden.
Variablennamen bestehen aus Buchstaben, Ziffern und dem Unterstrich, wobei ein Name nicht mit einer Ziffer beginnen darf. In der Tcsh existiert keine (praktische) Begrenzung der Länge von Variablennamen. Als Faustregel gilt, dass Umgebungsvariablen aus Groß- und lokale Variablen aus Kleinbuchstaben bestehen, aber die Shell selbst setzt diesbezüglich keine Vorschriften.
Expansionen der Tcsh |
Initialisierung |
Bei der interaktiven Arbeit mit der Tcsh zeigt die Shell ihre Bereitschaft zur Entgegennahme von Eingaben anhand eines Prompts (»Eingabeaufforderung«) an. Drei Prompts werden unterschieden, wobei zwei die Eingabeaufforderung symbolisieren:
Formatsequenzen:
:
Dieses »Kommando« tut nichts, außer einen Rückgabewert »0« zu erzeugen (»0« ist der übliche Rückgabewert eines Kommandos unter Unix, wenn seine Ausführung erfolgreich war). Nützlich ist es in Shellskripten, falls Sie in Bedingungen einen wahren Wert (»true«) benötigen oder an Positionen, wo syntaktisch ein Kommando erwartet wird, Sie aber keines benötigen:
user@sonne> while : ;do echo "Eine Endlosschleife"; done Eine Endlosschleife Eine Endlosschleife Eine Endlosschleife ... Eine Endlosschleife[Ctrl]+[C] user@sonne> if test -a foo ; then :; else echo "Datei nicht existent"; fi Datei nicht existent |
Interaktive Tcsh |
Die History |
Der Kommandozeilenspeicher (History) verwaltet die Liste vormals eingegebener Kommandos. Sie kann sowohl als Referenz der bisherigen Kommandofolge als auch als eine Art Baukasten zur komfortablen Zusammenstellung neuer Kommandozeilen dienen.
Zum Betrachten des aktuellen Inhalts des Kommandozeilenspeichers steht das eingebaute Kommando history zur Verfügung:
sonne /home/user> history | head 1 12:46 setenv TERM '`/bin/ls -l / > /dev/tty`' 2 12:46 set autologout = "10 5" 3 12:46 echo $status 4 12:46 repeat 3 sleep 1 5 12:46 time | echo 6 13:01 set foo = "this \ and that" 7 13:01 set foo = "this \ and that" ; 8 13:02 echo "$foo" ; |
In der Voreinstellung werden die letzten 100 Kommandos aufgelistet. Durch Angabe der Anzahl als letztes Argument von »history« kann die Länge der Ausgabe variiert werden.
Des Weiteren versteht »history« folgende Optionen:
-c
-h [n]
-r [n]
-T [n]
-S [Dateiname]
-L Dateiname
-M Dateiname
Zahlreiche Shellvariablen beeinflussen den Kommandozeilenspeicher. Dazu zählen:
histchars
histdup
histfile
histlit
history
savehist
Durch die Liste der Kommandos in der History und innerhalb einer Kommandozeile können Sie komfortabel mit Hilfe der Pfeiltasten und von Tastenkombinationen navigieren:
, [Ctrl][P]
, [Ctrl][N]
[Home]
[End]
Obige Tastenkombinationen beschreiben die Voreinstellung. Mittels dem eingebauten Kommando bindkey ist eine Änderung der Belegung möglich.
Eine Suche im Kommandozeilenspeicher wird ebenso angeboten:
Muster[Alt][p]
Muster[Alt][n]
Das Muster kann die Metazeichen »*«, »?«, »[]« und »{}« umfassen, allerdings betrifft dann die Suche nicht den Zeilenanfang sondern die gesamte Zeile. »echo« und »echo*« führen bspw. beide zur letzten Kommandozeile, die mit »echo« startete. »*echo« listet jedoch einzig eine Zeile auf, die mit »echo« endete. Um die Kommandozeile zu finden, die »echo« an beliebiger Position enthielt, ist folgende Eingabe erforderlich:
sonne /home/user> *echo*[Alt][p] sonne /home/user> grep -q foo bla | echo "huchuuuu" |
Eine History-Substitution wird mit dem so genannten »Bang-Operator« (!) eingeleitet. Die Art der Substitution schreiben die nachfolgenden Zeichen vor. Um keine History-Substitution handelt es sich jedoch, wenn dem »Bang-Operator« ein Whitespace, ein Gleichheitszeichen oder eine öffnende runde Klammer folgt (dann handelt es sich um einen unären Operator [Negation]).
Folgende Ausdrücke gestatten die Ausführung von Kommandozeilen aus der History ohne deren vorherige Manipulation:
!!
!n
!-n
!Präfix
!?Muster?
Einige Beispiele dazu:
sonne /home/user> cat foo # Ausgabe des Inhalts von »foo« sonne /home/user> !! | wc -l cat foo | wc -l 26 sonne /home/user> history | head -5 1 12:39 cal 2 12:39 ( cd ; make ) 3 12:50 vi ~/foo.cpp 4 12:50 history --help 5 12:50 g++ ~/foo.cpp -o ~/foo sonne /home/user> !4 history --help Benutzung: history [-chrSLMT] [# Anzahl der Befehle]. sonne /home/user> !vi vi ~/foo.cpp |
Die Wiederverwendung alter Kommandos nach obigem Substitutionsschema reißt sicher niemanden vom Hocker. Worin sollte der Vorteil gegenüber der Navigation im Kommandozeilenspeicher bestehen, die sogar das Editieren alter Einträge ermöglicht?
Die weit reichenden Möglichkeiten der Substitution nutzen erst die Erweiterungen zum Bang Operator - so genannte Wortselektoren. Sie gestatten die Verwendung von Teilen eines vorherigen Kommandos in der aktuellen Kommandozeile. Eingeleitet wird eine solche Erweiterung durch einen Doppelpunkt, der dem Bang Operator und dem Muster, das das alte Kommando referenziert, folgt. Ein Beispiel ist hoffentlich verständlicher als meine Umschreibung:
sonne /home/user> echo "1 2" 3 "4 5 6" 1 2 3 4 5 6 sonne /home/user> echo !!:3 4 5 6 |
Der Ausdruck »!!:3« wurde durch das dritte Argument des vorhergehenden Kommandos substituiert. Zugegeben... es ist kein sinnvolles Beispiel. Aber es ist einfach und sollte leicht zu verstehen sein. Der Zweck heiligt die Mittel.
Folgende Aufzählung benennt sämtliche Erweiterungen, mit denen Bestandteile von History-Einträgen extrahiert werden können.
n
-n
n-
m-n
^
$
*
%
Hierzu wieder einige Beispiele:
# Netzwerkschnittstelle initialisieren sonne /root> ifconfig eth0 192.168.100.100 up ... # ... Netzwerkschnittstelle runter fahren sonne /root> !ifc:-1 down ifconfig eth0 down # PDF-Version der Fibel erzeugen sonne /home/user> htmldoc --book --webpage -f Linuxfibel.pdf toc.htm einleitung.htm # ...125 weitere Dateien # Upps... eine Datei vergessen;-) sonne /home/user> !!:-4 default.htm !!:5-$ |
Ganz schön verwirrend... oder? Aber es kommt noch besser! Sie sind nicht einmal darauf angewiesen, die Argumente in ursprünglicher Form zu verwenden, sondern Sie können diese mit verschiedensten Modifizierern auch noch zuvor bearbeiten. Vorab die Liste der Modifizierer:
:e
:h
:p
:q
:r
:s/x/y/
:t
:x
:&
Und zum Abschluss wiederum einige Anwendungsbeispiele obiger Modifizierer:
sonne /home/user> ls /home/tux/komplizierterPfad/komplexerName /home/tux/komplizierterPfad/komplexerName sonne /home/user> cp !!^ !!^:t cp /home/tux/komplizierterPfad/komplexerName komplexerName sonne /root> cp -r /etc/skel /home/user sonne /root> !!:-$:s/user/tux/ cp -r /etc/skel /home/tux sonne /root> !!:-$:s?tux?&racer? cp -r /etc/skel /home/tuxracer |
Für die Zeichenkettenersetzung im vorhergehenden Kommando existiert ein spezieller Modifizierer. Roots Kopieroperationen in obigem Beispiel hätten auch wie folgt substituiert werden können:
sonne /root> cp -r /etc/skel /home/user sonne /root> ^user^tux cp -r /etc/skel /home/tux sonne /root> ^tux^&racer cp -r /etc/skel /home/tuxracer |
Diese Kurzform eignet sich also wirklich nur, wenn das vorherige Kommando mit genau einem geänderten Argument zu wiederholen ist.