Die Go-basierte Shell Elvish ermöglicht komplexe Programmstrukturen, die sich deutlich von jenen klassischer Kommandozeilen abheben.
Die Shell gehört zu den ältesten interaktiven Schnittstellen zum Computer. Sie hat zwei Aufgaben: Zum einen dient sie der direkten Ein- und Ausgabe im Zusammenspiel mit Programmen, zum anderen als Interpreter für Batch-Jobs oder Skripte. Die Funktion der interaktiven Eingabe bleibt bis heute unverändert bestehen, während für das Skripting zunehmend moderne Sprachen mit leistungsfähigeren Funktionen und einfacher strukturiertem Code zum Einsatz kommen. Entsprechend ihrer Bedeutung ging die Arbeit an den Shells stetig weiter. Die Entwickler erweiterten die Möglichkeiten, was die Kommandozeile aber zunehmend komplexer machte.
Unter Linux genießt die Bourne Again Shell (Bash) eine hohe Verbreitung, viele Distributionen richten sie als Standard-Shell für Anwender ein. Die Bash gilt als leistungsfähig und als zwar komplex, aber weitgehend zuverlässig. Inzwischen gibt es zahllose Alternativen, wie etwa die Csh (C-like shell), Tcsh, Dash, Dsh (Dancer’s Shell), Ksh (Korn Shell), Heirloom Shell, Fish (“User friendly shell”), Msh, Osh (Python-programmierte Shell), Pdksh und Psh (Parallel Shell) und die – ziemlich überfrachtete – Zsh (Z Shell). Eine gute Übersicht und Zusammenfassung zahlreicher bekannter Shells und ihrer Zwecke finden Sie online [1].
Neue Ideen
Der Unterbau der Bash lässt klare Strukturen weitgehend vermissen, die Shell wurde über die Jahre an allen Ecken und Enden erweitert. Insbesondere die diversen Erweiterungen der Bash machen die Syntax teils schwer verständlich und unübersichtlich. Daneben fehlt es ihr wie vielen anderen Shells an modernen Datentypen. So führte die Bash etwa Arrays erst vor einigen Jahren ein.
Bis heute kämpfen Anwender mit den Folgen der gewachsenen Strukturen gängiger Shells, die Skripte fehleranfällig und manchmal unleserlich machen. Bei Elvish [2] gingen die Entwickler deshalb einen anderen Weg: Sie wollten zunächst eine ausdrucksstarke, strukturierte Programmiersprache bereitstellen. Gleichzeitig versucht Elvish, die bei den bisherigen Shells verwendeten Konzepte und Techniken weiterhin bereitzustellen, um die Akzeptanz bei den Entwicklern und Administratoren zu erhöhen. In vielen Situationen imitiert die Software dazu das Verhalten klassischer Shells, etwa bei bekannten Tastenbindungen.
So erlaubt [Strg]+[R] die Suche rückwärts in der History, [Meta]+[B] schneidet ein Wort links vom Cursor aus und speichert es im Zwischenspeicher. In anderen Bereichen übernimmt Elvish Konzepte von anderen Programmen, etwa durch den Navigator-Modus ([Strg]+[N]). Tabelle “Voreingestellte Tastenkürzel” fasst die wichtigsten Tastenbindungen zusammen.
|
Kürzel |
Funktion |
|---|---|
|
[Tab] |
Komplettieren von Befehlen und Argumenten |
|
[Strg]+[N] |
Navigator-Modus |
|
[Umschalt]+[ß] |
Suche in der History |
|
[Umschalt]+[ß][Umschalt]+[ß] |
Bewegen in der Befehlszeile |
|
[Umschalt]+[ß] |
Befehlszeile in der History |
|
[Esc] |
History-Suche abbrechen |
|
[Strg]+[H] |
versteckte Dateien anzeigen |
|
[Eingabe] |
Auswahl übernehmen |
|
[Alt]+[Eingabe] |
mehrfache Auswahl übernehmen |
|
[Strg]+[L] |
Locations zeigen (verwendete Verzeichnisse) |
|
[Strg]+[M] |
Suchmodus |
|
[Strg]+[R] |
History-Suchmodus |
|
[Strg]+[U] |
bis zum Zeilenanfang löschen |
|
[Strg]+[K] |
bis zum Zeilenende löschen |
|
[Alt]+[**1**] |
letzte Befehlszeile wiederholen |
|
[Strg]+[V] |
Inhalt des Clipboards einfügen |
|
[Strg]+[C] |
Abbruch |
|
[Strg]+[D] |
beendet Elvish |
|
[Strg]+[I] |
Befehlskomplettierung |
|
[Strg]+[J] |
wie [Eingabe] |
Obwohl Elvish in etlichen Bereichen die Konzepte der klassischen Shells übernimmt, hält es dieses Konzept nicht komplett durch. So erfolgen etwa Berechnungen in der wenig intuitiven Prefix-Notation (auch: umgekehrte polnische Notation [3]), bei der der Operator vor den Operanden steht. Um etwa eins und eins zusammenzuzählen, tippen Sie in Elvish + 1 1.
Einstieg
Einige wenige Distributionen offerieren bereits Elvish-Pakete, bei Arch Linux genügt der Aufruf yaourt elvish zur Installation. Trotzdem müssen Sie die Shell nur im Ausnahmefall selbst übersetzen: Auf seiner Download-Seite [4] stellt das Elvish-Projekt statisch kompilierte Binaries zum Herunterladen bereit.
Neben Versionen für 32- und 64-Bit-Linux finden sich auch solche für ARM64, MacOS und Windows. Sie laden einfach den entsprechenden Tarball herunter, entpacken ihn in ein beliebiges Verzeichnis und starten dann auf einer Konsole das entpackte Binary. Sie landen daraufhin direkt am Elvish-Prompt.
Möchten Sie Elvish lieber selbst kompilieren, laden Sie statt der Binaries das Quelltext-Archiv herunter. Zum Übersetzen benötigen Sie die Programmiersprache Go ab Version 1.8. Haben Sie die entsprechende Toolchain eingerichtet, installieren Sie Elvish mit folgendem Befehl:
$ go get github.com/elves/elvish
Schon der erste Kontakt mit Elvish ist überraschend und sehenswert. Haben Sie die Software ins System integriert, starten Sie sie im Terminal mittels elvish. Sofort erscheint der für Elvish typische doppelte Prompt (Abbildung 1). Dessen beide Seiten stellen Sie bei Bedarf nach Ihren speziellen Vorstellungen ein. Das Elvish-Cookbook [5] zeigt ein Beispiel für die linke (Listing 1, erste Zeile) und rechte Seite (zweite Zeile).

Abbildung 1: Elvish verwendet einen frei konfigurierbaren doppelten Prompt, bei dem ein Teil der Informationen an der rechten Seite des Terminals steht.
Listing 1
edit:prompt = { tilde-abbr $pwd; put '? ' }
edit:rprompt = (constantly (edit:styled (whoami)?(hostname) inverse))
Dabei verändern die Funktionen edit:prompt und edit:rprompt den linken beziehungsweise rechten Teil des Prompts. Zwischen den Klammern steht jeweils der Code, mit dem Sie das Aussehen gestalten. Dabei wertet $pwd die Variable $PWD aus dem Environment aus; (whoami) und (hostname) rufen die entsprechenden externen Befehle auf und setzen deren Ausgaben an den jeweiligen Stellen ein. Mit inverse vertauschen Sie die Farben für Vorder- und Hintergrund.
Neben diesen beiden Prompt-Teilen taucht in manchen Situationen noch ein spezieller Prompt auf, den unter anderem der eingebaute Put-Befehl nutzt. Er hat die Form einer nach rechts gerichteten Pfeilspitze und kommt beispielsweise zum Einsatz, um die Inhalte von Variablen auszugeben. Über die eingebaute Variable $value-out-indicator definieren Sie das Zeichen bei Bedarf um.
Wie bei anderen Shells lassen sich auch in Elvish Befehle mit dem Tabulator komplettieren. Dabei dürfen Sie direkt mit den Pfeiltasten in den Befehlszeilen navigieren. Unter der aktuellen Befehlszeile zeigt die Shell die Nummer des gerade bearbeiteten Eintrags an. Mittels eines Fragezeichens ([Umschalt]+[ß]) starten Sie eine Suche in der Liste der Befehle. Die Position in der Befehlszeile steuert dabei, ob Sie den Namen von Befehlen oder Argumenten komplettieren. Eine Erklärung in der Form COMPLETING mit zusätzlichen Angaben zeigt dabei an, was gerade genau geschieht.
Eine für weniger versierte Anwender sehr schöne Methode, den Überblick in einem Dateisystem zu behalten, bietet das Navigieren (Abbildung 2). Über [Strg]+[N] aktivieren Sie diese Ansicht, wählen mit den Pfeiltasten beliebige Einträge aus und übernehmen sie durch einen Druck auf die Eingabetaste in die Befehlszeile.

Abbildung 2: Suchen Sie nach einem Dateinamen, bietet sich der Einsatz des integrierten Dateibrowsers an, über den Sie bei Bedarf den Namen eines Files in die Befehlszeile übernehmen.
Elvish sucht beim Programmstart im Home-Verzeichnis nach der Konfigurationsdatei .elvish/rc.elv, die analog zur .bashrc der Bash funktioniert.
Funktionen
Wie bei anderen Shells dienen bei Elvish Funktionen als schnelle Alternative zu externen Befehlen. Listing 2 zeigt die Syntax für eine Funktionsdefinition. Mit dem Schlüsselwort fn leiten Sie die Anweisung ein. Alle Argumente stecken im Array @a, durch $@a fügen Sie diese in den Code ein.
Listing 2
fn Funktionsname [Argumente] {Code}
Das Dollar-Zeichen referenziert dabei wie gewohnt Variablen. Vorsicht ist geboten, wenn Sie Funktionen mit dem Namen bestehender Befehle definieren, etwa im Rahmen einer Befehlsalternative. In der Bash bewirkt die Anweisung alias rm='rm -i' beispielsweise, dass rm vor dem Löschen nachfragt, ob Sie die angezeigte Datei auch tatsächlich entfernen wollen.
Bei Elvish führt der auf den ersten Blick identisch erscheinende Code aus der ersten Zeile von Listing 3 dagegen zu einer endlosen Rekursion. Die zweite Zeile zeigt die korrekt funktionierende Variante. Das führende e: im Code sorgt hier dafür, dass Elvish den externen Befehl rm ausführt und nicht die gleichnamige Funktion.
Listing 3
fn rm [@a] {rm -i $@a}
fn rm [@a] {e:rm -i $@a}
In Funktionen dienen Pipelines oft als wichtiger Transportweg für Daten. Die üblichen, Byte-orientierten Pipelines eignen sich jedoch nicht für strukturierte Daten, weshalb Elvish sie erweitert. Das erlaubt Ihnen, strukturierte Daten direkt auszugeben.
Neben Namensräumen sowie Funktionen, die Funktionen als Argumente verarbeiten, stellt Elvish auch Ausnahmen (Exceptions) bereit. Außerdem ermöglicht die Shell Closures sowie weitere Konstrukte, die Sie von modernen Programmiersprachen erwarten dürfen.
Eingebautes
Wie alle modernen Shells verfügt Elvish über eine große Anzahl eingebauter Befehle, die sogenannten Builtins. In der aktuellen Version stehen rund 100 eingebaute Befehle und acht Variablen bereit. Eine Übersicht über die Befehle erhalten Sie durch Eingabe von builtin:, gefolgt von einem Druck auf die Tabulatortaste.
Die eingebauten Funktionen teilen sich in mehrere Gruppen auf. Dabei muss eine ganze Reihe von Befehlen schon deswegen eingebaut sein, weil sie Shell-Interna nutzen oder verändern. Bei Elvish kommen viele Befehle hinzu, die mit den neuen Datenstrukturen arbeiten, diese anlegen, ausgeben und manipulieren.
Von den Funktionen der gängigen Shells unterstützt Elvish nur einen kleinen Ausschnitt, wie etwa cd, echo, exec und exit. Dafür bietet es die normalerweise nur als externe Befehle bereitgestellten Kommandos (e)awk, join(s) und split(s) in Form von Builtins.
Schleifen bauen Sie durch Schlüsselworte wie repeat, range, while, for und try (wie in Python) auf. Die dafür vorgesehenen Strukturen finden Sie in der ausführlichen Beschreibung der Sprache [6]. Auch ein If-Statement fehlt nicht. Zusätzlich gibt es noch einige als intern gekennzeichnete Befehle: -gc (Go-Garbage-Collector zum Debuggen), -ifaddrs (IP-Adresse des lokalen Hosts), -log (interne Log-Files), -stack (zeigt den aktuellen Stack), -source (führt Elvish-Skripten aus, -src-name enthält deren Namen) und -time (Laufzeitmessung analog zu time).
Neben eingebauten Befehlen verfügen Shells über eingebaute Variablen. Das ist bei Elvish nicht anders, obwohl hier nur eine sehr kleine Menge davon bereitsteht: $_ (verwirft den Inhalt), $false und $true für die entsprechenden booleschen Werte und $ok für Exceptions. Die Variablen $path, $pid und $pwd erfüllen die bekannten Funktionen.
Besonderheiten
Für Programmierer interessant: Elvish unterstützt über das Builtin run-parallel das parallele Abarbeiten von Befehlen. Listing 4 zeigt die einfache Syntax; die Shell führt dabei alle angegebenen Befehle aus und wartet, bis diese sich beendet haben.
Listing 4
run-parallel Befehl Befehl [...]
Gegenüber klassischen Shells weist Elvish eine ganze Reihe von syntaktischen Besonderheiten auf, die dem Anwender in manchen Fällen das Leben erleichtern. Ein typisches Beispiel liefern die Anführungszeichen: Sie kommen bei klassischen Shells an verschiedenen Stellen in der Befehlszeile zum Einsatz, um Argumente zu begrenzen oder den Effekt von Sonderzeichen aufzuheben.
Bei Elvish gelten die folgenden Regeln: Alles zwischen einfachen Hochkommas repräsentiert sich selbst, es handelt sich also um literale Elemente: echo '$literal' erzeugt also die Ausgabe $literal. Dagegen gibt echo $literal den Inhalt der Variablen $literal aus.
Benötigen Sie ein literales Hochkomma, erzeugen Sie dieses im Kontext durch Verdopplung: echo '''' gibt ' aus, denn die beiden äußeren Hochkommas schließen das auszugebende Material ein, zwei einfache Hochkommas gibt die Shell als eines aus.
Zwischen doppelten Hochkommas stehen die aus der Programmiersprache C bekannten Escape-Sequenzen bereit. So interpretiert die Shell "\n" als Zeilenumbruch, "\t" als Tabulator, und "\\" erzeugt einen sichtbaren Backslash.
Ansonsten haben doppelte Hochkommas keine besondere Funktion. Das bedeutet, dass Elvish den Ausdruck "$Variable" als $Variable interpretiert. Ähnliches gilt für den Backslash: Die Anweisung echo \* erzeugt oft eine Warnung Exception: wildcard has no match, weil nur das Sternchen als Wildcard wirkt.
Einer Variablen weisen Sie wie üblich durch Gleichheitszeichen einen Wert zu: var = Wert. Zusätzlich funktionieren Zuweisungen in der Form a b = 1 3. Der eingebaute Befehl put gibt bei Bedarf die zugehörigen Werte aus: put $a liefert also in diesem Beispiel 1, put $b den Wert 3.
Dabei spielt es eine Rolle, ob Sie vor und nach dem Gleichheitszeichen Leerraum verwenden. Schreiben Sie Wert und Variable direkt an das Zeichen, erzeugt die Shell eine temporäre Variable. Diese darf sogar denselben Namen tragen, wie eine bereits vorhandene, überschreibt diese aber nicht dauerhaft.
Bei Umgebungsvariablen geben Sie den Namensraum als E (Environment) an. So erfolgt der Zugriff auf den $PATH durch put $E:PATH.
Fazit
Viele Entwickler halten es schon lange für überfällig, die klassischen Shells durch ein modernes, übersichtlicheres und damit weniger fehleranfälliges Konstrukt zu ersetzen. Elvish macht einen Versuch in diese Richtung, geht den Weg allerdings aus Sicht des Anwenders nicht konsequent zu Ende.
Tatsächlich wendet sich die Shell in erster Linie an Entwickler oder Programmierer, die von den neuen Strukturen profitieren. Für normale Anwender bietet sie nur bedingt Vorteile: Die Struktur erscheint zu komplex, und zu vieles fehlt, wie etwa einfache Alias-Konstrukte. Der Einsatz von Namensräumen sorgt zwar für mehr Möglichkeiten, ist aber für alltägliche Anwendungen eher überdimensioniert.
Einen der häufigsten Fehler in der Open-Source-Welt versuchen die Entwickler jedenfalls zu vermeiden: Sie dokumentieren ihre Arbeit ausführlich und geben dabei sogar einen Einblick in die Gedanken, die zum Entstehen des Designs geführt haben [7].
Infos
-
Shell-Übersicht: https://github.com/oilshell/oil/wiki/ExternalResources
-
Elvish: http://elvish.io
-
Prefix-Notation: https://de.wikipedia.org/wiki/Umgekehrte_polnische_Notation
-
Download-Seite: http://elvish.io/download
-
Cookbook: https://elvish.io/learn/cookbook.html
-
Referenz: http://elvish.io/ref/language.html
-
Philosophie: http://elvish.io/philosophy





