In der Linuxwelt gibt es einen großen Grad an Freiheit. Die Freiheit der Wahl. Das ist nicht immer von Vorteil, zum Beispiel, wenn man mal wieder leidlich darüber diskutieren möchte, welcher Texteditor der bessere sei, welche Distribution die beste sei, welche Programmiersprache und warum um alles in der Welt KDE besser sei als Gnome. Und welche Shell genutzt werden müsse.
Doch da ist die Antwort für mich neuerdings leicht gefunden: zsh. Warum? Weil das Ding eine phänomenal geniale Befehlsvervollständigung hat ohne, dass ich mich umgewöhnen müsste. Sie ist einfach die bessere bash.
Befehlsve…<TAB>
Irgendwie war es für mich nie ein Thema, einen Gedanken daran zu verwenden, welche Shell ich nutzen wollte. Solange ich Linux nutze, benuzte ich stets bash und ich habe auch nie den Blick über den Tellerrand gewagt. Wozu auch, die bash tat jahrelang solide ihre Arbeit – von Windows kommend ist sie an Features nicht vergleichbar mit einer DOS Kommandozeile (ja, sowas gabs damals noch!) und auch sonst lässt sie wenig Wünsche offen.
Das sind denkbare schlechte Voraussetzungen für ein (für mich) neu entdecktes Programm, eine Chance zu erhalten sich zu beweisen, es sei denn es überzeugt auf den ersten Blick. Das mag wohl daran gelegen haben, dass ich die Alternativen nicht kannte, schlicht weil ich mich nie dafür interessierte. Dabei hätte sich der Blick gelohnt.
Die Z-Shell (zsh) kann nämlich noch viel mehr, ohne aufdringlich zu sein oder andere Paradigmen zu verfolgen, wie andere Shells (allen voran csh basierte Derivate und Originale). Das beste an ihr ist nämlich: Sie verhält sich weitestgehend kompatibel zur alten, bekannten bash. Alt ist in diesem Kontext vielleicht nicht unbedingt korrekt, denn sowohl die “Z-Shell”, als auch die “Bourne Again Shell” werden stetig und parallel weiterentwickelt und haben beide schon viele Jahre Entwicklung hinter sich.
Dennoch: Wer bash kennt, den wird zsh nicht verstören – oberflächlich fallen die Unterschiede nicht einmal auf und die zsh verhält sich sehr ähnlich eben zur Linux-Standardshell und man wird womöglich gar nicht bemerken, dass man eine andere Shell benutzt. Wenn man aber möchte, macht die zsh viele Dinge leichter im täglichen Prompt-Wahnsinn.
Das ist wichtiger als es scheint, denn als Linux-Systemadministrator verbringt man den Großteil des Tages in eben jener Shell und mit keinem Programm hat man mehr zu tun, als mit der Shell und dem Terminal Emulator darum herum. Es wird also Zeit, mit ein paar Dingen aufzuräumen und mir selbst das Leben leichter zu machen.
Ja – ich bin mir sicher, weniges von dem, was ich nun vorstelle sind zsh-exklusive Funktionen und womöglich kann man auch der bash das eine oder andere davon beibringen. Das ist aber auch nicht der Punkt, auf den ich hinaus will. Übrigens: Ich hörte letztens auch die Beschwerde, zsh würde zuviel für den Anwender denken. Dem kann man aber entgegnen, dass die zsh niemanden zu etwas zwingt. Alles, was ich vorstelle ist selbstverständlich deaktivierbar – genauso wie viele andere Optionen auch, die ich hier gar nicht erwähne. Eine Liste an (deaktivierbaren) Funktionen habe ich weiter unten gelinkt.
Einige der hier genannten Funktionen müssen explizit aktiviert werden, das funktioniert am einfachsten über eine Initialisationsdatei, die von zsh beim start gelesen und ausgeführt wird. Analog zu bashs .bashrc heißt die bei zsh .zshrc. Meine Version der zshrc ist als Download gelinkt.
- Grafisches Auswahlmenü:Für den Fall, dass die Befehlsvervollständigung nicht eindeutig ist, zeigt die Z-Shell auf Wunsch ein navigierbares Auswahlmenü an, durch das ich sowohl ganz gewohnt mit <TAB> springen kann, als auch mit Pfeiltasten navigieren.
- Rechtschreibkorrektur Ja es nervt. Manche Befehle sind kryptisch, manche Buchstaben liegen auf dem Keyboard zu nahe beeinander. Zum Glück weiß das auch zsh und korrigiert für mich Tippfehler nach einer “nearest match” Heuristik:
- Gleichzeitige Nutzung der History Datei: Nichts ist nerviger an der bash, als festzustellen, dass ein zuletzt eingegebener Befehl in der History-Datei verschwunden ist, weil eine Sitzung von konkurrierend geöffneten bash-Instanzen (z.B. in grafischen Umgebungen mit Terminalemulatoren) überschrieben wurde. Die Z-Shell hingegen schreibt Befehle durchgängig in die History-Datei, genau so wie sie über mehrere Fenster hinweg eingegeben wurden.
Apropos History – auch die Befehle in der Eingabegeschichte können bei der Wiederausführung ganz einfach verändert werden. Das ist eine äußerst nützliche Sache, wenn man Befehle in Massen, leicht verändert, ausführen möchte. Zum Beispiel so:
[arno@snowball:~/zsh]$ ssh root@host 'uptime' 01:12:55 up 119 days, 13:20, 0 users, load average: 0.08, 0.05, 0.05 [arno@snowball:~/zsh]$ r host=anotherhost ssh root@anotherhost 'uptime' 01:13:53 up 224 days, 12:21, 2 users, load average: 0.00, 0.00, 0.00
- Erwachsenes Globbing: Es ist ja bekannt, dass Shells Parameter automatisch einfügen können, sofern diese auf ein Muster passen. rm -rf * ist jedem bekannt. Selbstverständlich funktioniert das auch so in zsh.
[arno@snowball:~/zsh]$ ls * zsh1.png zsh2.png zsh3.png zsh4.png zsh5.png zsh6.png zsh7.png zsh8.png
Soweit dürfte das Linux-Nutzer nur langweilen. Spannender wird es, wenn ich aber erwähne, dass dies natürlich nicht alles ist. Ich kann zum Beispiel noch komplexe Muster anbieten:
[arno@snowball:~/zsh]$ ls zsh[2-4].png zsh2.png zsh3.png zsh4.png
Oder Alternativen:
[arno@snowball:~/zsh]$ touch foo; touch bar [arno@snowball:~/zsh]$ ls (foo|bar) bar foo
Oder Negation:
[arno@snowball:~/zsh]$ ls bar foo zsh1.png zsh2.png zsh3.png zsh4.png zsh5.png zsh6.png zsh7.png zsh8.png [arno@snowball:~/zsh]$ ls ^*.png bar foo
Oder rekursive Suche:
[arno@snowball:~/zsh]$ mkdir -p eine/sehr/tiefe/verzeichnishierarchie [arno@snowball:~/zsh]$ touch eine/sehr/tiefe/verzeichnishierarchie/foobar [arno@snowball:~/zsh]$ ls **/foo* eine/sehr/tiefe/verzeichnishierarchie/foobar
zsh fragt übrigens auch nach, wenn es nicht sicher ist, ob es einen Befehl wirklich ausführen soll, weil der potentiell viel Schaden anrichtet. Zum Beispiel eben erwähntes rm *:
[arno@snowball:zsh/p]$ touch a b c d e f g h i [arno@snowball:zsh/p]$ ls a b c d e f g h i [arno@snowball:zsh/p]$ rm * zsh: sure you want to delete all the files in /home/arno/zsh/p [yn]?
- Parametervervollständigung: Die meisten modernen Kommandozeileneingaben beherrschen mittlerweile die Befehlsvervollständigung. Angefangen bei ausführbaren Befehlen und Dateien und Ordnern. Das beherrscht jede Shell – doch zsh geht deutlich weiter und ermöglich auch die Vervollständigung von Eingaben, die weit über das hinausgehen, was man von den meisten anderen Shells kennt. Nichts ist langweiliger, als sich ständig durch Manpages und Hilfsausgaben zu wühlen, weil man den Namen eines Schalters vergessen hat. Zum Glück gibts da Abhilfe:
Selbstverständlich funktioniert das auch für komplexere Kommandozeileneingaben:
- Parametervervollständigung Variante Binford 6000: Wem das bereits vorgestellte nicht innovativ genug ist, der hat vermutlich noch nie versucht, zshs Vervollständigung wirklich auszureizen. Zum Beispiel ist es möglich für apt-get Paketnamen zu vervollständigen:
Noch immer nicht genug? Wie wäre es mit SSH-Hostnamen Vervollständigung (hier oder hier). Der Vollständigkeit halber sollte vielleicht erwähnt werden, dass es eine gute Idee ist, die known_hosts Datei zu hashen, sodass ich persönlich diese Funktion daher nicht nutze. Dennoch kann zsh hier auch ganz ohne Hostname Vervollständigung entfernte(!) Pfade vervollständigen (wenn sich zsh einloggen kann – z.B. über serverseitig hinterlegte Public Keys):
Aber auch lokal sind zshs Möglichkeiten noch nicht ausgereizt, ich kann zum Beispiel die für kill benötigte Prozess-ID automatisch von zsh vervollständigen lassen. Es nervt nämlich gewaltig, dass kill keine Prozessnamen akzeptiert und diese stets vorher mit Hilfsmitteln gesucht werden müssen (etwa pidof, grep, …). Zum Glück weiß das auch zsh und wer möchte kann ja mal versuchen zum Beispiel “kill icew<TAB>” tippen:
- Globale Aliases: Die meisten Shells haben irgendeine Form von Aliases. Damit ist es ganz einfach möglich, neue Befehle aus komplexeren zusammenzusetzen, oder neue zu erzeugen. Zum Beispiel so:
[arno@snowball:zsh/p]$ alias ll='ls -l' [arno@snowball:zsh/p]$ ll insgesamt 0 -rw-r--r-- 1 arno arno 0 13. Aug 01:28 a -rw-r--r-- 1 arno arno 0 13. Aug 01:28 b -rw-r--r-- 1 arno arno 0 13. Aug 01:28 c -rw-r--r-- 1 arno arno 0 13. Aug 01:28 d -rw-r--r-- 1 arno arno 0 13. Aug 01:28 e -rw-r--r-- 1 arno arno 0 13. Aug 01:28 f -rw-r--r-- 1 arno arno 0 13. Aug 01:28 g -rw-r--r-- 1 arno arno 0 13. Aug 01:28 h -rw-r--r-- 1 arno arno 0 13. Aug 01:28 i
Das ist nun nicht revolutionär. Diesen Anspruch erfüllt jedoch das globale Aliasing, das zsh zusätzlich beherrscht. Damit kann jeder beliebiger Parameter abgekürzt werden, der an Befehle übergeben werden kann (Vorsicht aber bei der Namensgebung um Kollissionen mit lokalen Dateien zu vermeiden!):
[arno@snowball:~/zsh]$ alias -g wgd=www.google.de [arno@snowball:~/zsh]$ ping -c2 wgd PING www.google.com (66.249.92.104) 56(84) bytes of data. 64 bytes from 66.249.92.104: icmp_seq=1 ttl=57 time=41.3 ms 64 bytes from 66.249.92.104: icmp_seq=2 ttl=57 time=39.9 ms --- www.google.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 39.996/40.659/41.322/0.663 ms
Oder für Dateien:
[arno@snowball:~/zsh]$ alias -g sl=/etc/apt/sources.list [arno@snowball:~/zsh]$ head -n2 sl deb http://ftp.de.debian.org/debian/ sid main non-free contrib deb-src http://ftp.de.debian.org/debian/ sid main non-free contrib
Oder für komplexere Pipelines:
[arno@snowball:~/zsh]$ alias -g pgrep='| grep --color=auto' [arno@snowball:~/zsh]$ dpkg -l pgrep zsh ii zsh 4.3.10-13 A shell with lots of features
- Verbessertes Verzeichnishandling: Die Z-Shell bringt auch einige Funktionen mit, die Verzeichniswechsel besonders einfach machen. Zum Beispiel die Möglichkeit, Verzeichnisse ohne Befehl zu wechseln:
[arno@snowball:~/zsh]$ ein [arno@snowball:zsh/ein]$ unterverzeichnis [arno@snowball:ein/unterverzeichnis]$ pwd /home/arno/zsh/ein/unterverzeichnis
Auch die Navigation über den Verzeichnisstapel ist besonders einfach. Genau wie bash, merkt sich auch zsh die Verzeichnisse, über die der Anwender navigiert ist.
[arno@snowball:~/zsh]$ pwd /home/arno/zsh [arno@snowball:~/zsh]$ cd ein/unterverzeichnis/und_noch_eines [arno@snowball:unterverzeichnis/und_noch_eines]$ pwd /home/arno/zsh/ein/unterverzeichnis/und_noch_eines [arno@snowball:unterverzeichnis/und_noch_eines]$ cd - ~/zsh [arno@snowball:~/zsh]$ pwd /home/arno/zsh [arno@snowball:~/zsh]$ cd -1 ~/zsh/ein/unterverzeichnis/und_noch_eines [arno@snowball:unterverzeichnis/und_noch_eines]$ pwd /home/arno/zsh/ein/unterverzeichnis/und_noch_eines
Das ganze lässt sich natürlich auch vervollständigen:
Dabei wird auch höflich nachgefragt, ob ich die Korrektur akzeptieren möchte (y), nicht korrigiert werden möchte (n oder STRG+C) oder die Korrektur gar immer (a) akzeptieren möchte. Falls mir die Alternativen allesamt nicht gefallen, kann ich auch den Prompt noch einmal bearbeiten (e).
und zwar nicht nur für Befehle, auch Pfade werden korrigiert:
Übrigens funktioniert diese Art der Fehlerkorrektur auch für “naheliegendste Treffer”, also nicht nur auf exakte Vervollständigungen, sondern auch für jene, die nur annähernd auf meine Befehlseingabe passen. Das ist zum Beispiel hilfreich, wenn man Pfade eingibt, die nicht existieren:
Ich will auch zsh!
Glückwunsch zu deiner Entscheidung. Die Installation erledigt deine Linux-Distribution, zsh wird sich im Standard Repertoire der meisten Distributionen befinden, in Debian reicht “apt-get install zsh“, garantiert zum letzten Mal ohne <TAB> in die Kommandozeile getippt. Danach kann zsh ganz einfach durch Eingabe des gleichnamigen Befehls über die bereits ausgeführte Login (Standard) Shell ausgeführt werden. Wer möchte, kann zsh natürlich auch zur Standardshell machen. Dazu entweder als root
[root@snowball:arno/zsh]$ usermod -s /bin/zsh benutzername
ausführen, oder – auch als nicht-privilegierter Benutzer – mit chsh:
[arno@snowball:~/zsh]$ chsh -s /bin/zsh
Der Start mit zsh kann etwas schwierig sein, weil die Shell eine ganze Menge an Optionen bietet und die Befehlsvervollständigung ist damit noch gar nicht abgedeckt. Mit zsh mit kommen auch einige Hilfsprogramme, die beim ersten Start (bzw. nicht gefundener .zshrc-Datei) Assistenten anbieten, die zsh Shell zu konfigurieren. Zu erwähnen wären hier vor allem drei Assistenten:
- zsh Konfiguration: Die grundsätzliche Konfiguration startet zsh automatisch beim ersten Start (zsh-newuser-install).
- compinstall: Konfiguration des Vervollständigungssystems. So mächtig das ist, so vielfältig auch die Konfigurationsmöglichkeiten. Der genannte Installationsassistent wird dieses Modul automatisch ausfühlen. Wer möchte, kann das aber auch manuell anstoßen:
- Promptkonfiguration: Ja der gute alte Prompt, der muss nicht nur hübsch aussehen, der muss auch genau die Information beinhalten, die der Benutzer haben möchte. Unglücklicherweise ist das für jeden Benutzer individuell. Daher gibt es Möglichkeiten sich seinen eigenen Prompt auszusuchen, oder ganz frei selbst zu gestalten – und in zsh gibt es wirklich viele Möglichkeiten den Prompt zu gestalten, eingeschlossen mehrzeiliger Prompts, Informationen am rechten Rand und was auch immer. Einen Einstieg gibt das Modul promptinit:
[arno@snowball:~/zsh]$ autoload -Uz compinstall [arno@snowball:~/zsh]$ compinstall
[arno@snowball:~/zsh]$ autoload -U promptinit [arno@snowball:~/zsh]$ promptinit
Danach listet prompt -p alle vorhandenen Themes und gibt die Möglichkeit dieses auch einzusetzen, falls man ein fertiges Thema verwenden möchte. Natürlich kann man $PS1 auch selbst konfigurieren.
Wer überhaupt nicht konfigurieren möchte und sich auf meine Allwissenheit verlässt, der kann auch meine zshrc benutzen. Einfach unter ~/.zshrc abspeichern und zsh starten. Ich habe auch versucht die Optionen, die ich nutze zu kommentieren.
zshrc (8.8 KiB, 982 hits)






















8 comments
1 ping
BuntspechT says:
August 14, 2010 at 19:13 (UTC 1)
Ich hab mir lange überlegt, ob ich bei der gewohnten bash bleibe, obwohl ich so viel gutes über zsh gelesen habe. Dein Beitrag hat mich zumindest dazu bewegt, mir mal zsh anzuschauen, ich bin gespannt, ob ich dabei bleiben werde ;)
Unabhängig davon ein sehr ausführlicher Post, der mal wieder erstklassig geschrieben ist!
ich says:
August 15, 2010 at 17:47 (UTC 1)
Dankeschön. Nun komme ich endlich dazu, zsh ausführlicher zu testen.
name says:
August 16, 2010 at 12:38 (UTC 1)
Gibt es (gravierende) Syntaxunterschiede zwischen bash und zsh?
Würden alle bash-Skripte Problemlos funktionieren?
Die kleinen Helferlein der zsh sind schon ganz nett aber ich würde ungern alle meine Skripte anpassen müssen.
Arno says:
August 16, 2010 at 21:12 (UTC 1)
Sofern du sh kompatibel schreibst auf jeden Fall. Wenn du bash-Dialekte benutzt, hast du zumindest sehr gute Chancen, dass deine Skripte weiter funktionieren.
Manuel says:
October 6, 2011 at 17:17 (UTC 1)
Solange die Bash installiert ist und die entsprechenden Scripte mit einem passenden Shebang notiert sind ist die kompabillität doch auch eigtl. wurscht
Moe says:
September 18, 2010 at 20:51 (UTC 1)
Das “erste Mal” mit der Zsh hatte mich damals ganz schön mitgenommen, sie war einfach zu einschüchternd. Dank Deinem Artikel hab ich sie mir nochmal vorgenommen und muss sagen, ich bin wirklich begeistert! Alles, was ich bei der bash vermisst habe, ist bei der Zsh vorhanden. Ähnlich erleuchtend wie der Umstieg von gedit auf Emacs :)
Robert says:
February 16, 2011 at 09:44 (UTC 1)
Der Downloadlink zur zshrc funktioniert leider nicht :(
Arno says:
February 17, 2011 at 00:18 (UTC 1)
Ist behoben, danke.
.zshrc | SUCKUP.de says:
September 17, 2010 at 19:43 (UTC 1)
[...] bis ins kleinste per .zshrc einstellen kann. Zum Schluss noch zwei hilfreiche Links zum Thema: zshdaemonkeeper.net/318/zsh-die-bessere-shellwiki.ubuntuusers.de/zshÄhnliche Blog-Einträge:SSH-Hostnamen vervollständigen Ports via ssh [...]