Freitag, 20. März 2009

Programmierbare Eingabe-Vervollständigung in Bash

1. Vorwort
Seit Version 2.04 verfügt die Bourne Again Shell (bash) über die Möglichkeit, die automatische Eingabe-Vervollständigung durch eigene Definitionen zu erweitern. Ein Tool, das hiervon intensiv Gebrauch macht, ist bash-completion. Es ist zu finden unter http://www.caliban.org/bash/index.shtml#completion. Bei Debian ist es bereits in das bash-Paket integriert, muß aber manuell aktiviert werden.
2. Installation
Das Paket muß lediglich heruntergeladen und entpackt werden, normalerweise ins Verzeichnis /etc. Das folgende Listing zeigt, wie die Eingabe-Vervollständigung aktiviert wird, nachdem man das Paket installiert hat. Es wird an /etc/bashrc angefügt. Bei Debian heißt die Datei /etc/bash.bashrc. Die bereits vorhandenen Zeilen zur Aktivierung, die auskommentiert sind, kann man löschen.
bash=${BASH_VERSION%.*}
bmajor=${bash%.*}; bminor=${bash#*.}
if [ "$PS1" ] && [ $bmajor -eq 2 ] && [ $bminor '>' 04 ] \
&& [ -f /etc/bash_completion ]; then # interactive shell
# Source completion code
. /etc/bash_completion
fi
unset bash bmajor bminor

Die Eingabe-Vervollständigung wird normalerweise mit der TAB-Taste aktiviert (auch das ist in »bash« konfigurierbar). Die Standardeinstellung ist, bei einer Mehrdeutigkeit nichts zu tun und erst bei einer zweiten Betätigung von TAB die Liste der möglichen Ergänzungen zu zeigen. Es ist empfehlenswert, das zu ändern. Dazu fügt man in /etc/inputrc (global für alle Benutzer) oder ~/.inputrc (für individuelle Benutzer) folgendes Kommando ein:
set show-all-if-ambiguous on

3. Was die Shell alleine kann
Was kann die Eingabe-Vervollständigung alles? Die folgende Beschreibung muß zwangsläufig unvollständig sein, da das Programm ständig weiter entwickelt wird.
Zunächst gibt es da die Standard-Features der Shell, die jeder, der mit der Shell gearbeitet hat, kennen dürfte. Sie stehen auch in der Manpage und im README von bash_completion.
Das erste Wort einer Zeile wird als Kommando interpretiert; hier tritt die Kommando-Vervollständigung in Kraft. Dabei sucht die Shell im ganzen Pfad sowie unter den Aliasen und Shell-Funktionen nach passenden Ergänzungen.
Alle folgenden Wörter sind Argumente des Kommandos. Oft sind das Dateinamen, daher bietet die Shell zur Vervollständigung die Dateinamen des aktuellen Verzeichnisses an. Natürlich kann man auch ein Verzeichnis angeben (z.B. /usr) und bekommt dann die Dateinamen unter /usr zur Auswahl.
Gibt man »~« ein und vervollständigt dann, so werden die Benutzernamen, die dem System bekannt sind, zur Auswahl angeboten. Beginnt das Argument dagegen mit »@«, dann versucht die Shell, dies zum Hostnamen zu ergänzen. Beginnt man mit »$«, dann wird bash versuchen, eine Umgebungsvariable zu ergänzen.
4. Die Erweiterungen von bash-completion
Set Version 2.04 gibt es das neue Shell-Kommando complete. Wenn man dieses ohne Argumente eingibt, erhält man entweder nichts oder eine Liste, die Zeilen wie die folgenden enthält und zunächst einmal nicht viel aussagt:
complete -o filenames -F _longopt ld
complete -F _kill kill
complete -F _renice renice
complete -j -P '%' jobs
complete -d pushd
complete -o filenames -F _filedir_xspec playmidi
complete -o filenames -F _filedir_xspec bzdiff
complete -o filenames -F _querybts querybts

Der Witz ist nun, daß die Ergänzung für jedes eingegebene Kommando (Sie erinnern sich? Das erste Wort einer Zeile) individuell konfiguriert werden kann. Das ist das letzte Wort jeder complete-Zeile im obigen Listing. Das Paket »bash-completion« bringt schon zahlreiche Definitionen mit, und es werden in jeder Version mehr.
Geht man z.B. in ein Verzeichnis mit einem Makefile und gibt make und ein TAB ein, dann erscheint als Auswahl eine Liste aller definierten Targets in dem Makefile, ohne daß man »less« oder einen Editor starten müßte, um die Datei anzusehen.
Gibt man ssh ein und danach TAB, dann wird die Liste der known_hosts gelesen und diese Hosts als Auswahl angeboten. Bei zahlreichen Programmen ist es möglich, -- als Argument anzugeben, und nach einem TAB erhält man eine Auswahl aller langen Optionen, die das Programm anbietet. Das ist sicherlich praktischer, als --help einzugeben oder die Manpage zu öffnen, um die richtige Option zu finden. Es funktioniert mit df, aber auch z.B. mit configure.
Komplettiert man unter Debian das Kommando reportbug, so erhält man eine Auswahl aller verfügbaren Debian-Pakete - das kann jedoch ein paar Sekunden dauern. Nach kill erhält man eine Liste der Prozeß-IDs. Nach ncftp, einem FTP-Client, erhält man eine Liste aller Bookmarks des Programmes. Nach tar und jar gibt die Komplettierung eine Liste von Kommandos an, die folgen können. Ich höre hier auf, bash-completion kann noch mit hunderten weiterer Kommandos umgehen.
5. Eigene Erweiterungen hinzufügen
»bash-completion« bietet schon unglaublich viel, aber sollten Sie dennoch etwas hinzufügen wollen, müssen Sie sich zunächst mit dem Shell-Kommando complete vertraut machen.
5.1. Das Kommando complete
Um complete zu verstehen, muß man zunächst die Manpage von bash(1) lesen. Denn die Hilfe mit help complete ist nicht ausreichend. Die Beschreibung findet sich im Abschnitt »Programmable Completion«. Die Argumente des complete-Kommandos sind unter »Shell Builtin Commands« erklärt. Das Kommando hat so viele mögliche Optionen, daß bald jeder Buchstabe belegt scheint. Viele davon stellen sich aber als Abkürzungen für andere heraus, so ist z.B. -g eine Abkürzung von -A group. Diese Option bewirkt, daß die möglichen Komplettierungen aus den auf dem System existierenden Gruppen bestehen.
Die grundsätzliche Syntax von complete ist einfach:
complete [ Optionen ] name [ name ... ]
Nach dem Kommando complete können also Optionen folgen, dann ein »name«, womit der Name eines Kommandos gemeint ist. Außerdem können weitere Namen folgen für Kommandos, die genauso wie das erste behandelt werden sollen.
Die wichtigsten Optionen sind:
-o comp_option Legt verschiedene Optionen für die Generierung von passenden Elementen fest. Die Einzelheiten sind in der Manpage zu finden.
-A action Erlaubt die Auswahl von vordefinierten Methoden, um passende Elemente zu finden. Man muß diese Option nicht verwenden, man kann z.B. auch -F oder -G einsetzen. Die Einzelheiten sind in der Manpage zu finden.
-G pattern Die Auswahl besteht aus den Dateinamen, die auf das Pattern passen.
-W wordlist Die Auswahl besteht aus den direkt angegebenen Wörtern. Beispielsweise sorgt -W "rot gelb" dafür, daß für eine Komplettierung genau die beiden Wörter »gelb« und »rot« zur Verfügung stehen.
-C command Das Kommando command wird in einer Subshell ausgeführt, und seine Ausgabe wird für die Komplettierungen verwendet.
-F function Die Shell-Funktion function wird ausgeführt (im gleichen Kontext wie die aktuelle Shell). Sie muß die möglichen Komplettierungen in die Array-Variable COMPREPLY schreiben, die dann ausgewertet wird. Das Interessante ist hier, welche Funktionen bash-completion bereits mitbringt. Leider ist mir keine ausführliche Dokumentation bekannt. Sie müssen in die Datei /etc/bash_completion hineinsehen. Die Funktionen beginnen mit _filedir und gehen bis zum Ende der Datei - mehr als 4000 Zeilen, die Ihnen zur Verfügung stehen.
-X pattern Aus der Auswahl werden die Elemente entfernt, die auf das Pattern passen. Dies ist also ein Filter.
-P prefix Prefix wird vor den Anfang jeder möglichen Komplettierung geschrieben, nachdem alle anderen Optionen verarbeitet sind.
-S suffix Suffix wird hinter jede mögliche Komplettierung geschrieben, nachdem alle anderen Optionen verarbeitet sind.
5.2. Schreiben eigener Komplettierungen
Mit diesem Wissen sollte es Ihnen leicht fallen, eigene Komplettierungen zu schreiben. Hier ein simples Beispiel. Ich benutze ein Skript namens publish, um Pro-Linux-Artikel für die Publikation fertig zu machen. publish erwartet als Argument eine HTML-Datei, und diese hat immer das Suffix .html. Was liegt also näher als die Dateinamens-Vervollständigung mit der Option -G auf Dateien mit dem Suffix .html einzuschränken? Hier ist das Kommando dafür:
complete -G '*.html' publish
Daß es funktioniert, kann man sofort feststellen. Man könnte noch die Option -o dirnames hinzufügen, um in dem Fall, daß keine HTML-Datei im aktuellen Verzeichnis liegt, die Unterverzeichnisse zur Auswahl zu bekommen. Im Allgemeinen mag das ratsam sein, doch bei meinem Programm macht das keinen Sinn, daher habe ich es weggelassen.
Sicher fallen Ihnen nun weitere Beispiele ein, vielleicht sogar solche, die für die Allgemeinheit nützlicher sind als meines :-)
5.3. Die Datei ~/.bash_completion
Wenn Sie jetzt eine eigene Komplettierung geschrieben haben, wohin damit? Man kann sie natürlich in ~/.profile eintragen. Ein besserer Platz laut FAQ scheint jedoch ~/.bash_completion zu sein. Wenn diese Datei noch nicht vorhanden ist, legen Sie sie einfach an und schreiben Ihr complete-Kommando hinein. Auch eventuelle Hilfsfunktionen können Sie hier unterbringen. Sie müssen die Datei ausführbar machen, sonst hat sie keinen Effekt.
Lizenz
Dieser Text unterliegt der GNU Free Documentation License (FDL). Freie Verbreitung in modifizierter oder unmodifizierter Form ist erlaubt; Modifikationen müssen unmissverständlich gekennzeichnet sein und ebenfalls unter der FDL vertrieben werden.
Copyright (C) hjb
Erschienen auf Pro-Linux, letzte Änderung 2003-05-25