Hardcore-Linux

Aus LinuxUser 07/2000

Hardcore-Linux

Die Bash, das unbekannte Wesen

In diesem ersten Teil einer Serie über die Bash verraten wir Ihnen erste Geheimnisse beim Umgang mit dem Befehlszeileninterpreter. Probieren Sie alles aus! Nur so kann man das erlernte Wissen behalten und vertiefen.

Ein Überblick

Der erste Kontakt mit einer Shell ist häufig ernüchternd: Sie haben ein Terminal gestartet und sehen (fast) nichts, nur einen Prompt. Das soll die hoch gelobte Shell sein?

In diesen und den folgenden Beispielen verwenden wir “$>” als Prompt. Bei Ihnen kann das – abhängig von der Konfiguration Ihrer Shell – etwas anders aussehen, z. B. so (oder noch ganz anders):

Wie man den Prompt ändert, verraten wir Ihnen in einem der folgenden Teile. Der Prompt wird im Deutschen als “Eingabeaufforderung” bezeichnet (bleiben wir lieber beim englischen Begriff) und signalisiert dem Anwender, dass er nun seine Befehle eingeben kann.

Eine Befehlszeile ist dabei etwa in der folgenden Weise aufgebaut:

Prompt Befehl Argumente und Optionen

Der genaue Aufbau einer Befehlszeile ergibt sich aus vielen Faktoren, die wir in den nächsten Teilen besprechen werden. Unter anderem spielt der angegebene Befehl eine Hauptrolle. Er bestimmt, welche Argumente und Optionen verwendet werden können. Befehlszeilen beginnen immer mit einem Befehlsnamen (oder einem Shell-abhängigen Spezialzeichen), der normalerweise direkt angegeben wird, oder mit seinem Pfad, falls es sich um einen externen Befehl handelt, der nicht im Suchpfad der Shell liegt.

Hardcore-Linux?

Die Artikel dieser Serie verlangen Ihnen mehr ab als die übrigen LinuxUser-Texte. Auch wenn Sie die Informationen teilweise unverständlich finden, sollten Sie sich davon nicht abschrecken lassen. Anhand der Beispiele können Sie die einzelnen Features der Shell ausprobieren und so einiges über den Umgang mit der Befehlszeile lernen.

Bearbeiten von Befehlszeilen

Befehlszeilen können editiert werden, solange sie nicht mit [Return] an die Shell übergeben wurden. Bis zu diesem Zeitpunkt handelt es sich quasi um eine normale Textzeile, wie sie auch in einen Editor eingegeben werden könnte. Dem Anwender stehen in der Eingabezeile eine Reihe von Editierfunktionen zur Verfügung, die durch verschiedene Tastenkombinationen aufgerufen werden.

Innerhalb einer Befehlszeile kann der Anwender mit den normalen Tasten arbeiten, vorausgesetzt sein Terminal und die Shell sind korrekt konfiguriert. [Pos1] lässt den Cursor an den Anfang der Befehlszeile springen, [Ende] an deren Ende. In der Bash können diese Aktionen auch durch [Strg+A] bzw. [Strg+E] ausgeführt werden. Hier zeigt sich ein grundlegendes Konzept der Bash: Die einzelnen Tastendrücke werden mit speziellen Funktionen verknüpft – “gebunden” heißt das im Fachjargon.

Die Bash verwendet die Funktionen der Readline-Library zur Bearbeitung der Befehlszeile. Die Funktion beginning-of-line ist an [Strg+A] gebunden, end-of-line an [Strg+E]. Diese Bindungen lassen sich auch vom Anwender verändern, siehe unten. Die Cursortasten [<–] und [–>] verschieben die Schreibmarke um jeweils eine Position. Das geht auch, wenn keine Cursortasten zur Verfügung stehen: [Strg+F] (forward-char) und [Strg+B] (backward-char) bewegen den Cursor. Auch wortweise kann der Cursor versetzt werden: [Meta+F] springt mit der Funktion forward-word nach rechts, [Meta+B] (backward-word) nach links. Da die meisten Tastaturen über keine “Meta”-Taste verfügen, emuliert Linux deren Funktion. Zum einen wird die linke Alt-Taste [Alt] als Meta-Taste belegt, zum anderen kann die Escape-Taste vor einer Meta-Tastenkombination betätigt werden. Also: die an [Meta+B] gebundene Funktion kann als [Alt+B] oder durch [Esc] mit anschließendem [B] ausgeführt werden.

Die [Einfg]-Taste sollte eigentlich den Überschreibmodus aktivieren, dies ist aber bei den wenigsten Terminals möglich. Meistens fügt diese Taste die zuletzt ausgeschnittene Textpassage links vom Cursor ein oder hat einfach gar keine Funktion. Dafür wird mit der [Entf]-Taste in den meisten Systemen das Zeichen unter dem Cursor oder links davon gelöscht.

Entsprechendes gilt für die [Backspace]- (Rückschritt-) Taste oben rechts über der Return-Taste. Welche Aktion diese Taste auslöst, kann der Anwender unter X im Terminalemulator meistens einstellen. Beim klassischen xterm entscheidet die Einstellung der Ressource backarrowKeyIsErase über deren Funktion. Einfacher ist die Einstellung bei den KDE-Terminals vom Typ kvt vorzunehmen: Dort kann mit dem Menüpunkt Terminal ein kleines Dialogfenster geöffnet werden, in dem verschiedene Einstellungen möglich sind.

"Konfiguration

Die Bash stellt Ihnen natürlich noch viel mehr Funktionen zur Verfügung: Sie können beispielsweise mit der an [Meta+Backspace] gebundenen Funktion das Wort links vom Cursor löschen und es später mittels [Strg+Y] (yank) erneut in die Befehlszeile einfügen. Das Löschen von Bereichen ist noch allgemeiner: mit [Strg+Leerzeichen] definieren Sie den Anfang eines Bereichs, setzen den Cursor auf das Ende des Bereichs und löschen den Text dazwischen mittels [Strg+W] (kill-region). Ein Beispiel verdeutlicht dies:

"Abbildung

$> dd if=/dev/urandom of=del1 count=3

Am Ende dieser Befehlszeile bemerkt der Anwender, dass er statt Daten aus dem Gerät urandom vielleicht doch lieber welche aus zero verwenden will. Er kann nun mittels backward-word dreimal nach links springen und landet dann auf dem “o” von “of”.

Mit der Tastenkombination [Meta+Backspace] entfernt er das falsche Wort urandom und gibt stattdessen zero ein. Dabei ist es ausreichend, wenn er ze gefolgt von der Tabulatortaste eintippt – die Bash komplettiert diese Angabe.

Durch das Return wird die geänderte Zeile ausgeführt. Die dabei ausgeführte Funktion heißt accept-line und ist neben [Return] ebenfalls an [Strg+J] und [Strg+M] gebunden. Auch das Löschen ab der Cursor-Position bis zum Zeilenende ist mit [Strg+K] (kill-line) vorgesehen, umgekehrt: Löschen bis zum Zeilenanfang erfolgt durch [Strg+U] (unix-line-discard).

Auf zwei Besonderheiten beim Editieren der Befehlszeile sollten wir noch hinweisen: Es gibt die Möglichkeit, in einer Befehlszeile mehr als eine Textpassage auszuschneiden. Alle ausgeschnittenen Passagen werden der Reihe nach in einem speziellen Speicher zwischengespeichert, dem kill-ring, siehe Abbildung 1. Jeweils die zuletzt gespeicherte Passage wird durch einen yank-Befehl ([Strg+Y]) vor der Cursor-Position eingefügt. Es besteht mittels [Meta+Y] die Möglichkeit, den kill-ring um eine Position zu rotieren, so dass die zuvor ausgeschnittene Passage eingefügt wird.

$>  mv  /etc/inputrc  /etc/inputrc.system

inputrc.system wird ausgeschnitten (z. B. mit [Meta+Backspace]), anschließend wird inputrc ausgeschnitten …

$>  cp  /etc/inputrc.system

der zuerst ausgeschnittene Text wird mit [Strg+Y] eingefügt …

$>  cp  /etc/inputrc.system  ~/.inputrc

[Meta+y] rotiert den kill-ring, und der zuletzt ausgeschnittene Text wird eingefügt.

So könnten also beispielsweise auch die Angaben einer Eingabedatei mit einer Ausgabedatei vertauscht werden. Der kill-ring-Speicher verfügt normalerweise über 30 Speicherplätze. Werden mehr Textpassagen ausgeschnitten, verschwinden die zuerst in den Speicher aufgenommenen. Zu einer Passage zählen alle nacheinander mittels einer der kill-Funktionen (kill-line, kill-region, kill-whole-line, kill-word, forward-/backward-kill-word, unix-line-discard und unix-word-rubout, nicht aber forward-backward-delete-char) gelöschten Texte, wenn keine anderen Funktionen zwischenzeitig ausgeführt wurden. Das Bewegen des Cursors mit den Cursortasten beispielsweise reicht aus, um eine kill-Aktion zu beenden. Wenn alles schief geht, gibt es eine Undo-Funktion für die Befehlszeile, die es ermöglicht, alle Änderungen schrittweise in umgekehrter Reihenfolge zurückzunehmen. Die Funktion undo ist, wie unten gezeigt wird, normalerweise an die Tastenkombination [Strg+Shift+-] (also: Strg, Shift und -) gebunden.

Alle Änderungen in der Befehlszeile können auch in einem Schritt revidiert werden, dies ist durchrevert-line – gebunden an [Meta+R] oder [Strg+Meta+R] möglich.

Die Editierfunktionen konfigurieren

Die an Tasten gebundenen Editierfunktionen können beim Start der Shell eingestellt und zur Laufzeit verändert werden. Die Voreinstellungen sind in der Datei /etc/inputrc vorhanden. Falls der Anwender eine eigene Anpassung vorgenommen hat, steht diese üblicherweise in der Datei ~/.inputrc. Beide Dateien werden in der angegebenen Reihenfolge eingelesen und ausgewertet. Mit dem bind-Befehl können Bindungen angezeigt, gelöscht oder neu angelegt werden. Allgemein lautet die Befehlssyntax:

bind "Taste" "Funktion"

Für Taste können einfache Tasten (z. B. i oder z) angegeben werden oder aber Funktionstasten und Tastenkombinationen. Vorbelegt sind diese Tasten mit den auf den Tastenkappen angegebenen Zeichen. Die dabei eingesetzte Funktion heißt self-insert. Besonders häufig werden für Editierfunktionen Kombinationen mit der [Strg]- oder [Meta]-Taste verwendet.

$> bind  '"\C-w" unix-word-rubout'

Mit dieser Befehlszeile wird die Funktion unix-word-rubout (sie löscht das Wort links vom Cursor) an die Tastenkombination [Strg+w] gebunden. Oft ist bereits die Funktion backward-kill-word an diese Tastenkombination gebunden. Beide Funktionen unterscheiden sich in den Zeichen, die Wortgrenzen, bis zu denen sie löschen, markieren.

Die [Strg]-Taste wird bei der Definition durch \C symbolisiert; für die [Meta]-Taste kann entsprechend \M oder \e ([Escape]) verwendet werden. Folgende weitere Tastenkürzel erkennt die Readline-Library:

Control ist die ausgeschriebene Form für die [Ctrl]- ([Strg])-Taste. Weitere symbolische Tastennamen, die durch die Readline-Library interpretiert werden können, sind: RUBOUT ([Backspace]), DEL ([Entf]), ESC ([Escape]), LFD, NEWLINE, RET, RETURN, SPC ([Leerzeichen]), SPACE, und TAB ([Tabulatortaste]).

Oft wird auch die kompakte Emacs-Schreibweise zur Spezifikation des Tastencodes eingesetzt:

"\M-\C-u": universal-argument

Die Funktion ist eine der inzwischen auf etwa 140 angewachsenen Anzahl interner Funktionen. Sie sollen hier nicht im Detail beschrieben werden. Sie sind in der man-Page zur Library und – meistens aktueller – in der entsprechenden info-Dokumentation beschrieben. Auf deutsch ist eine Beschreibung mit vielen Beispielen in [2] enthalten.

Die Optionen von bind sind: -l (list) erzeugt eine Liste aller verfügbaren Funktionen. -p und -P (print bindings) stellt die momentan eingestellten Bindungen dar. Die von -p verwendete Darstellungsform kann zum Erzeugen einer Eingabedatei verwendet werden.

$> bind -p
"\C-g": abor
"\C-x\C-g": abor
"\e\C-g": abor
"\C-j": accept-line
"\C-m": accept-line
"\eOM": accept-line
# alias-expand-line  (not  bound)
...
"a": self-inser
"b": self-inser
"c": self-inser
"d": self-inser
...
$> bind -P
abort can be found on "\C-g", "\C-x\C-g", "\e\C-g".
accept-line can be found on  "\C-j", "\C-m", "\eOM".
alias-expand-line is not bound to any keys
arrow-key-prefix is not bound to any keys
...

-f Konfigurationsdatei

Mit dieser Option wird die im Argument angegebene Konfigurationsdatei eingelesen und ausgewertet. Das entspricht dem Einlesen von inputrc-Dateien. Die einfache Möglichkeit, derartige Konfigurationsdateien zu erzeugen, besteht in der Modifikation der aktuellen Konfiguration:

$> bind -p > ~/.inputrc

(Eingabedatei erzeugen)

$> emacs ~/.inputrc

(Eingabedatei bearbeiten und speichern)

$> bind -f ~/.inputrc

(Eingabedatei einlesen) Für das Einlesen und Auswerten der Standardkonfigurationsdateien existiert eine eigene Funktion (re-read-init-file). Sie ist üblicherweise an [Strg+X] [Strg+R] gebunden.

-r Taste (remove) löscht die Bindung einer Funktion von der angegebenen Taste.

-u Funktion (unbind) löst die Bindungen dieser Funktion.

-q Funktion (query): Mit dieser Option können die Tasten erfragt werden, an die die angegebene Funktion gebunden ist:

$> bind -q undo
undo can be invoked via "\C-x\C-u",  "\C-_".

In diesem Beispiel kann die Funktion undo sowohl über [Strg+Y],[Strg+U] (nacheinander), als auch über [Strg+_] aufgerufen werden.

-v und -V zeigen die Readline-Variablen an, mit -V erfolgt die Ausgabe dabei im internen Format:

$> bind -v
set completion-ignore-case off
set convert-meta off
set disable-completion off
set enable-keypad off
set expand-tilde off
set horizontal-scroll-mode off
set input-meta on
set mark-directories on
set mark-modified-lines off
set meta-flag on
set output-meta on
set print-completions-horizontally on
set show-all-if-ambiguous on
set visible-stats on
set bell-style audible
set comment-begin #
set completion-query-items 111
set editing-mode emacs
set keymap emacs

-s und -S haben dieselben Funktionen für Readline-Makros.

Variablen der Readline-Library

Variablen der Readline-Library bestimmen maßgeblich das Verhalten ihrer Funktionen. Folgende Variablen sind vorhanden, die Voreinstellungen werden in Klammern gezeigt:

  • completion-ignore-case (off): Groß- Kleinschreibung wird bei der Komplettierung ignoriert
  • input-meta (off): Erlaubt die Verwendung von 8-Bit codierten Eingabezeichen
  • meta-flag (off): Synonym für input-meta
  • convert-meta (on): 8-Bit-kodierte Zeichen durch Streichen des höchstwertigen Bit konvertieren
  • disable-completion (off): Ausschalten der Komplettierungsfunktionen. Die Tabulatortaste wird dann als Tabulatorzeichen interpretiert.
  • enable-keypad (off): Deaktiviert zusätzliche Tasten einer erweiterten Tastatur
  • expand-tilde (off): Tilde-Expandierungen ausschalten
  • horizontal-scroll-mode (off): off bewirkt, dass überlange Zeilen automatisch umbrochen werden, on aktiviert eine Scrollfunktion
  • mark-directories (off): Kennzeichnet Verzeichnisse durch einen abschließenden Slash (/), wenn sie durch die Komplettierungsfunktionen dargestellt werden
  • mark-modified-lines (off): Bei der Ausgabe von Historyzeilen werden modifizierte Zeilen mit einem “*” gekennzeichnet, wenn diese Variable auf on gesetzt wurde
  • output-meta (off): stellt 8-Bit-Zeichen als 7-Bit-Zeichen mit einem Prefix dar; durch on werden sie direkt ausgegeben
  • bell-style (audible): steuert die Wirkung des Bell- (Signal-) Zeichens:
  • none: Bell-Zeichen werden vollständig ignoriert.
  • visible: Die Ausgabe erfolgt in Form einer visible bell, durch das Aufblitzen des Bildschirms.
  • audible: Das Bell-Zeichen wird als Ton akustisch ausgegeben. Tonhöhe und -dauer bestimmen die Voreinstellungen.

*

show-all-if-ambiguous (off): Voreingestellt wird eine Warnung ausgegeben, wenn mehr als eine Komplettierung möglich ist; on unterdrückt diese.

  • visible-stats (off): on kennzeichnet den Dateityp bei der automatischen Darstellung durch die Komplettierungsfunktionen.
  • comment-begin (#): definiert das als Kommentarzeichen interpretierte Zeichen
  • completion-query-items (100): stellt die maximale Anzahl von Komplettierungsmöglichkeiten ein, die ohne Rückfrage sofort angezeigt werden
  • editing-mode (emacs): steuert die Editierfunktionen des Interfaces
  • keymap (emacs): die Tastaturbindungstabelle. Mögliche Angaben: emacs, emacs-meta, emacs-ctlx, emacs-standard, vi, vi-command, vi-insert.

Mindestens die folgenden drei Angaben sollten immer aktiviert sein, sie ermöglichen erst die Verwendung von 8-Bit-Zeichen (z. B. Umlauten!) auf der Shell:

set meta-flag on
set output-meta on
set convert-meta off

Neu ist die Variable print-completions-horizontally. Sie steuert die Darstellungsrichtung der Komplettierungsmöglichkeiten erst horizontal print-completions-horizontally: on.

$> kl[Tab]
klaser.kss    klines.kss     klipper
klissie.kss   kljettool      klocate
klock         klogconsole    klogd
klp           klpq           klyx

oder erst vertikal mit print-completions-horizontally: off:

$> kl[Tab]
klaser.kss   kljettool    klogd
klines.kss   klocate      klp
klipper      klock        klpq
klissie.kss  klogconsole  klyx

Voreingestellt ist die zweite Variante (off).

Auch die Readline-Variablen lassen sich mit bind setzen. Dazu wird die interne Funktion set aufgerufen, der als erstes Argument der Variablenname und als zweites der zugewiesene Wert folgt. Alle drei Angaben werden zwischen Hochkommata eingeschlossen, damit die Shell sie als ein Argument (das des bind-Befehls) erkennt.

$> bind 'set completion-query-items 111'
$> bind -v
...
set bell-style audible
set comment-begin #
set completion-query-items 111
set editing-mode emacs
...

Komplettierungen

Die Bash kann viele Teile der Befehlszeile automatisch ergänzen, indem sie den Kontext untersucht und auswertet. Bei der Bash wird die Tabulatortaste für diese Funktion eingesetzt. Ein Beispiel verdeutlicht dieses Feature:

$> cd /e[Tab]tc/
$> mo[Tab]re print[Tab]cap

In der ersten Zeile ergänzt die Bash nach dem Betätigen der Tabulatortaste den Pfadnamen, der eindeutig ist. Etwas schwieriger wird das in der zweiten Zeile: Auch hier komplettiert die Bash zunächst einen Befehlsnamen, dann einen Dateinamen. Oft gibt es aber mehr als einen Befehl, der durch Ergänzen der eingegeben Buchstaben erzeugt werden kann. Das Beispiel sieht bei mir so aus:

$> mo[Tab](BEEP)[Tab]
moc         mode3                modemlights`apple
mogrify     montage              more
mount       mouse-properties-capple

Der Signalton zeigt an, dass das Komplettieren nicht (eindeutig) möglich ist. Nach dem Eingeben eines weiteren Buchstaben r reichen die Informationen aus, um den Befehlsnamen zu komplettieren. Vorteilhaft ist bei diesem Verfahren, dass mittels [Tab] automatisch die richtige Schreibweise des Befehlsnamen ergänzt wird und dass die Bash auch ein Leerzeichen im Anschluss automatisch einfügt.

Neben den Komplettierungen von Befehls- und Datei- bzw. Verzeichnisnamen kann die Bash auch noch Variablen-, Rechner- (so, wie sie in der Datei /etc/hosts vorhanden sind) und Usernamen (wie in /etc/passwd) ergänzen.

Das automatische Ergänzen wird von mehreren Funktionen und Bash-Variablen gesteuert. Wenn die Anzahl der möglichen Ersetzungen einen voreingestellten Wert (Readline-Variable completion-query-items, typischerweise 100) überschreitet, fragt die Bash nach, ob wirklich alle Möglichkeiten angezeigt werden sollen:

$> j[Tab]
Display all 252 possibilities? (y or n)

Oben wurde schon auf die Readline-Variable show-all-if-ambiguous hingewiesen, die dieses Verhalten zusätzlich steuert. Weitere Shell-Variablen spielen bei der Komplettierung eine Rolle: So enthält die Variable GLOBIGNORE eine Liste von Mustern, die Namen definiert, die nicht automatisch expandiert werden, extglob steuert die erweiterte Musterauswertungen; das Setzen von dotglob verhindert, dass auch Dateinamen, die mit einem Punkt (dot) beginnen, erzeugt werden, und weiteres mehr. Auf diese Punkte gehen wir in einem späteren Teil ein. Erwähnenswert sind noch die Readline-Funktionen, mit denen spezielle Komplettierungen durchgeführt werden können. Die an der aktuellen Cursor-Position möglichen automatisch ermittelten Komplettierungen zeigt [Meta+?] an. Dabei findet eine einfache interne Auswertung der Befehlszeile statt. An der ersten Position werden Befehlsnamen ergänzt, danach kontextabhängig Datei-, Variablen- oder andere Namen:

$> cp k[Tab]
...

(abhängig vom aktuellen Verzeichnis)

Für die Bestimmung des Typs der Komplettierung nutzt die Bash den bereits vorhandenen Text, deshalb liefern die folgenden Befehlszeilen ganz unterschiedliche Ergebnisse:

$> cp ~k[Tab]arsten
$> cp $K[Tab]DEDIR
$> cp root@k[Tab]arsten

In manchen Fällen ist die automatische Komplettierung aber nicht sinnvoll, wie folgendes Beispiel zeigt:

$> which kj[Meta+!]ukebox

Hier soll unabhängig von der Position in der Befehlszeile ein Befehlsname (which bestimmt den Pfad des als Argument angegebenen Befehls) eingefügt werden, dies geschieht durch die Funktion complete-command. Analoge Funktionen sind an folgende Tastenkombination gebunden:

  • [Meta+/] (complete-filename),
  • [Meta+@] (complete-hostname),
  • [Meta+$] (complete-variable) und
  • [Meta+~] (complete-username).

Von besonderer Bedeutung sind noch [Meta+{] (complete-into-braces) und [Meta+?] (possible-completions). Letztere Funktion zeigt eine Liste aller Komplettierungsmöglichkeiten, ohne sie in die Befehlszeile einzufügen; mittels complete-into-braces werden die vorhandenen Komplettierungen in einer speziellen Form dargestellt. (Das Ausprobieren dieser Funktion überlassen wir Ihnen…)

Alle bereits einmal ausgeführten Befehlszeilen werden in einem Speicher – dem History-Buffer – aufbewahrt. Der nächste Teil dieser Serie beschäftigt sich u. a. mit den Möglichkeiten dieses Features.

Infos

[1] K. Günther: Kompaktreferenz Linux, MITP 2000

[2] Zilm, Th., Grelck, K.: Linux – die Userreferenz, MITP 1999

LinuxUser 07/2000 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben