Die Standardshell auf den meisten Linux-Systemen ist die Bash. Sie ist schon sehr mächtig und erlaubt es viele Aufgaben zu automatisieren. Dieser Artikel soll sich einer sehr interessanten weil noch mächtigeren Shell widmen, der Z-Shell kurz zsh.
Die zsh lässt sich auf quasi allen Linuxsystemen über die Paketverwaltung installieren. Unter Ubuntu z.B. mit dem Befehl
Danach kann man sie mit dem Aufruf von zsh
ausführen. Um sie zur Standardshell zu machen genügt der Befehl
chsh -s /usr/bin/zsh username
Wobei username
durch den entsprechenden Usernamen ersetzt werden muss und der Pfad zu zsh
stimmen muss. Auf manchen Systemen liegt zsh
in /bin
. Wo zsh
liegt kann man mit dem folgenden Befehl heraus finden:
Die zsh bedient sich Elementen der Bash, der Korn-Shell (ksh) und der TENEX-C-Shell (tcsh – eine erweiterte C-Shell). Sie ist sehr gut konfigurierbar und fast jedes Verhalten der Bash kann nachgeahmt werden so dass der Umstieg sehr leicht fällt. Bestehende Bash-Scripte können natürlich weiterhin genutzt werden, wenn der Shebang entsprechend gesetzt ist. Also in der ersten Zeile folgendes steht:
Im Folgenden werde ich einige interessante Vorteile der zsh kurz beschreiben. Zu einzelnen Themen werde wahrscheinlich in anderen Artikel ausführlicher eingehen. Dies sollen also nur Beispiele sein, die die Mächtigkeit demonstrieren sollen. Da die zsh so viele Möglichkeiten bietet ist es nicht möglich hier alles im Detail zu erläutern. Optionen werden mit dem Befehl setopt
gesetzt. Dies kann man auch so in die Konfigurationsdatei ~/.zshrc
schreiben.
Autokorrektur
Die zsh beherrscht einen Mechanismus, der kleine Tippfehler automatisch korrigiert. Hat man in einem Ordner eine Datei testfile.txt
und möchte diese kopieren nach file2.txt
, so führt man in der Regel folgenden Befehl aus:
cp testfile.txt file2.txt
wie von der Bash gewohnt nutzt man dafür die Autovervollständigung mittels TAB. Bei einem Verschreiber wird dieser in der zsh automatisch korrigiert. Beispiel:
wird automatisch korrigiert und zu
vervollständigt.
Die Autokorrektur aktiviert man mit der Option correct
Globale Aliase
Neben den normalen Aliasen für Kommandos, wie man sie aus der Bash kennt, gibt es in der zsh noch globale Aliase, die überall im Befehl genutzt werden können, nicht nur am Anfang. Zwei Beispiele verdeutlichen dies:
alias -g G='| grep'
alias -g L='| less'
erzeugt die globalen Aliase G und L die man hinter alle möglichen Befehle schreiben kann um die Ausgabe des entsprechenden Befehls in grep oder less zu pipen. Z.B.
entspricht dem Befehl
oder
entspricht
Natürlich ist auch folgendes Möglich:
was folgendem Befehl entspricht:
Suffix Aliase
Mit Suffixaliasen kann man Programme festlegen, mit denen bestimmte Dateitypen (anhand ihrer Endung) geöffnet werden sollen. Man braucht dann nur noch den Namen der Datei eingeben und sie wird mit dem entsprechenden Programm geöffnet. Beispiel:
legt einen Alias für pdf Dateien an. Sie sollen mit evince geöffnet werden. Danach reicht die Eingabe von
und die Datei dokument.pdf
wird mit evince geöffnet.
Aliase für Verzeichnisse: Hashes
Mit sogenannten Hashes lassen sich Aliase für beliebige Verzeichnisse anlegen. Auf diese kann dann sehr einfach zugegriffen werden. Mit dem Befehl
hash -d perl=~/developement/scripting/perl
legt man einen Hash namens perl
für das Verzeichnis ~/developement/scripting/perl
an. Auf dieses Verzeichnis kann man jetzt mit ~perl
zugreifen. Auch innerhalb eines Befehls wie folgendes Beispiel zeigt:
Dieser Befehl kopiert die Datei testscript.pl
in das Verzeichnis ~/developement/scripting/perl
.
Auto-CD
Mit der Option autocd
kann man zum Wechseln in ein Verzeichnis einfach den Namen eines Verzeichnisses eingeben und das Kommando cd
davor einfach weglassen. Wenn es keinen Befehl gibt, der so heißt wie das Verzeichnis, so wird in das Verzeichnis gewechselt.
Kurze for-Schleifen
Statt einem
for i in *.eps; do epstopdf $i; done
um alle eps-Dateien in einem Verzeichnis in pdf-Dateien umzuwandeln genügt unter zsh die kürzere Form
for i (*.eps) epstopdf $i
Globale History
Die History, die man mit der Pfeil-auf Taste durchgehen kann, kann man in der zsh so einstellen, dass sie in jeder zsh-Instanz gleich ist. Das heißt man hat nicht mehr für jedes Fenster seine eigene History sondern kann mit der Pfeil-auf Taste auch Befehle raussuchen, die in anderen Fenstern eingegeben wurden. Die History wird jedoch nur nach jedem Befehl geupdated, das heißt man muss ggf. einmal Return drücken, damit die Befehle aus einem anderen Fenster verfügbar sind.
Dieses Verhalten kann mit der Option share_history
aktiviert werden.
Directory Stack
Wie Bash, hat die zsh auch einen Directory stack. Mit dem Befehl pushd
kann man das aktuelle Verzeichnis auf den Stack legen und mit popd
das jeweils letzte Verzeichnis vom Stack nehmen und dorthin springen. Mit der Option auto_pushd
legt die zsh automatisch jedes Verzeichnis auf den Directorystack, aus welchem man in ein anderes Verzeichnis wechselt. So hat man immer eine History der Verzeichnisse in denen man war und kann mit popd
sehr einfach wieder in Verzeichnisse welchseln, die man vorher besucht hatte.
Globbing
Die Nutzung von Wildcards – unter zsh globbing genannt – ist bei der Z-Shell wesentlich mächtiger als in der Bash. Zunächst gibt es rekursives Globbing (gibts in der Bash in neueren Versionen wohl auch). So kann man mit dem Befehl
alle HTML-Dateien im aktuellen Verzeichnis und allen Unterverzeichnissen auflisten lassen.
Es gibt jedoch auch noch Qualifier um Dateien mit bestimmten Eigenschaften auszuwählen. Diese schreibt man in runde Klammern. So kann man mit .
normale Dateien, mit /
Verzeichnisse und mit @
Symbolische Links matchen. Praktisch ist das z.B. wenn man allen Verzeichnissen ab einem bestimmten Verzeichnis die Rechte 755 und allen Dateien 644 vergeben möchte. Dies kann man mit den folgenden zwei Befehlen bewerkstelligen statt mit find
und exec
zu arbeiten.
chmod 755 **/*(/)
chmod 644 **/*(.)
Zusätzlich gibt es auch Qualifier für verschiedenste Dateirechte. Folgender Befehl listet alle Dateien auf, die von allen beschrieben werden können:
Auch nach der Dateigröße lässt sich suchen:
listet alle leeren Dateien auf.
Auch die Sortierung lässt sich beliebig anpassen. Mit dem Befehl:
Listet alle Dateien der Größe nach von klein nach groß auf. Mit großem O wird die Sortierung umgekehrt.
Somit lässt sich mittels globbing in der zsh das Kommando find
quasi komplett ersetzen. Die hier gezeigten Beispiele sehen auf den ersten Blick recht kompliziert und kryptisch aus. Wenn man das Prinzip aber einmal verstanden hat und die wichtigsten Qualifier kennt ist es aber ganz einfach und sehr praktisch.
Es gibt noch jede Menge weiterer Qualifier und Möglichkeiten für das Globbing (z.B. nur das erste oder eine bestimmte Anzahl von Elementen auszuwählen), die ich hier gar nicht alle erwähnen kann. Im zsh-Manual gibt es jedoch eine Liste der Glob-Qualifier.
Um alle Möglichkeiten nutzen zu können sollte die Option extended_glob
gesetzt werden.
Vervollständigung
Die zsh hat wie die Bash einen Vervollständigungsmechanismus, so dass man mit der TAB-Taste Kommandos, Dateinamen und vieles mehr vervollständigen kann. In der zsh ist dieser Mechanismus jedoch extrem gut konfigurierbar und programierbar. So kann man z.B. beim scp
Befehl (der Dateien über ssh kopiert) die Verzeichnisse auf dem entfernten Rechner vervollständigen und genau definieren welche Programme mit welchen Dateitypen zusammen arbeiten können. Für sehr viele Programme ist dies schon vorgefertigt, so dass ein
automatisch zu
vervollständigt wird. Dies beherrscht die Bash zum Teil auch. Jedoch ist es in der zsh wesentlich besser konfigurierbar und anpassbar.
Sehr praktisch finde ich auch die Menüfunktion. So wird beim ersten Druck auf die TAB-Taste wie in der Bash soweit vervollständigt, bis nicht mehr entschieden werden kann welche Datei (bzw. welcher Befehl) gemeint ist. Ein weiterer Druck auf die TAB-Taste listet alle weiteren Möglichkeiten auf und jeder weitere Druck geht diese Möglichkeiten durch. Wenn ich also drei Dateien habe: test.txt
, testfile1.txt
und testfile2.txt
und gebe folgendes ein:
so wird zuerst auf test
vervollständigt. Ein weiterer Druck gibt mir alle Möglichkeiten aus:
testfile1.txt testfile2.txt test.txt
und ein dritter Druck auf die Tab-Taste vervollständigt den Befehl zu
Das ist viel schneller als erst ein f
einzugeben um erneut TAB zu drücken und dann die 1
einzugeben um wiederum TAB zu drücken bis der Dateiname endgültig vervollständigt wird.
Ein weiterer Druck auf TAB nimmt dann die nächste Möglichkeit. In diesem Beispiel also
und so weiter.
Expansion
Mit der TAB-Taste kann man in der zsh nicht nur Kommandos, Dateinamen, … vervollständigen, sondern auch Variablen expandieren. Viele kennen ja die spezielle Variable !!
, die den zuletzt ausgeführten Befehl enthält. In der zsh kann man nun folgendes eingeben:
und die Variable !!
wird automatisch zum zuletzt ausgeführten Befehl expandiert. Genauso kann man auch jede andere Variable expandieren:
wird zu /home/zimon/developement
(vorrausgesetzt ich befinde mich zum Zeitpunkt der expansion in diesem Verzeichnis).
History Kontrolle
Wie bei der Bash auch, kann man in der zsh die History durchsuchen. Die zsh geht jedoch so weit, dass man auch nach bestimmten Parametern suchen kann. Ein Beispiel:
cp ../perl/foo.pl ~/developement/projektordner
Danach kommen ein paar andere Kommandos. Möchte nun eine andere Datei in den gleichen Projektordner kopieren reicht folgende Eingabe:
cp ../perl/bar.pl !?proj?:3
Mit !? wird nach einem vorherigen Befehl gesucht. Das proj
ist ein String der in diesem Befehl vorkam. Mit dem ?:3
wird das dritte Argument genutzt. Durch die Expansion kann manmit durch einen Druck auf TAB diesen Ausdruck auch noch expandieren um sicher zu gehen, dass das richtige Argument ausgewählt wurde. Man kann zwar mit Alt+. wie in der Bash die jeweils letzten Argumente durchgehen, auf diese Weise kann man aber auch das zweite von drei Argumenten suchen.
Es gibt noch wesentlich mehr Möglichkeiten die History zu durchsuchen und zu verwenden.
Hochkonfigurierbarer Prompt
In der Z-Shell kann man nicht nur die linke Seite des Prompts sondern auch die rechte Seite konfigurieren. Als Beispiel hier mal mein aktueller Prompt:
Mein aktueller zsh-Prompt
Ich finde die Anzeige der Uhrzeit inklusive Sekunden recht praktisch, da man daran sieht wie lange ein Befehl gedauert hat oder wann man ihn ausgeführt hat. Es gibt jedoch auch die Möglichkeit automatisch die Ausgabe von time
bei der Beendigung eines Befehls ausgeben zu lassen, der länger als eine vorher definierte Zeit benötigt hat.
Der Prompt ist eine abgeänderte Version von Phil!s ZSH Prompt.
[UPDATE] Auf Anfrage hin ist hier noch der Code für die von mir abgeänderte Version des Prompts:
setprompt () {
###
# Need this so the prompt will work.
setopt prompt_subst
###
# See if we can use colors.
autoload colors zsh/terminfo
if [[ "$terminfo[colors]" -ge 8 ]]; then
colors
fi
for color in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE; do
eval PR_$color='%{$terminfo[bold]$fg[${(L)color}]%}'
eval PR_LIGHT_$color='%{$fg[${(L)color}]%}'
(( count = $count + 1 ))
done
PR_NO_COLOUR="%{$terminfo[sgr0]%}"
###
# See if we can use extended characters to look nicer.
typeset -A altchar
set -A altchar ${(s..)terminfo[acsc]}
PR_SET_CHARSET="%{$terminfo[enacs]%}"
PR_SHIFT_IN="%{$terminfo[smacs]%}"
PR_SHIFT_OUT="%{$terminfo[rmacs]%}"
PR_HBAR=${altchar[q]:--}
PR_ULCORNER=${altchar[l]:--}
PR_LLCORNER=${altchar[m]:--}
PR_LRCORNER=${altchar[j]:--}
PR_URCORNER=${altchar[k]:--}
if [[ "$TERM" == "screen" ]]; then
PR_HBAR=-
PR_ULCORNER=--
PR_LLCORNER=--
PR_LRCORNER=--
PR_URCORNER=-
fi
###
# Decide if we need to set titlebar text.
case $TERM in
xterm*)
PR_TITLEBAR=$'%{\e]0;%(!.-=*[ROOT]*=- | .)%n@%m:%~ | ${COLUMNS}x${LINES} | %y\a%}'
;;
screen)
PR_TITLEBAR=$'%{\e_screen \005 (\005t) | %(!.-=[ROOT]=- | .)%n@%m:%~ | ${COLUMNS}x${LINES} | %y\e\\%}'
;;
*)
PR_TITLEBAR=''
;;
esac
###
# Decide whether to set a screen title
if [[ "$TERM" == "screen" ]]; then
PR_STITLE=$'%{\ekzsh\e\\%}'
else
PR_STITLE=''
fi
###
# Finally, the prompt.
PROMPT='$PR_SET_CHARSET$PR_STITLE${(e)PR_TITLEBAR}\
$PR_RED$PR_SHIFT_IN$PR_ULCORNER$PR_BLUE$PR_HBAR$PR_SHIFT_OUT(\
$PR_GREEN%(!.%SROOT%s.%n)$PR_GREEN@%m:%l\
$PR_BLUE)$PR_SHIFT_IN$PR_HBAR$PR_RED$PR_HBAR${(e)PR_FILLBAR}$PR_BLUE$PR_HBAR$PR_SHIFT_OUT(\
$PR_MAGENTA%$PR_PWDLEN<...<%~%<<\
$PR_BLUE)$PR_SHIFT_IN$PR_HBAR$PR_RED$PR_URCORNER$PR_SHIFT_OUT\
$PR_RED$PR_SHIFT_IN$PR_LLCORNER$PR_BLUE$PR_HBAR$PR_SHIFT_OUT(\
%(?..$PR_LIGHT_RED%?$PR_BLUE:)\
${(e)PR_APM}$PR_YELLOW%D{%H:%M:%S}\
$PR_BLUE)$PR_SHIFT_IN$PR_HBAR$PR_SHIFT_OUT\
$PR_RED$PR_SHIFT_IN$PR_HBAR$PR_SHIFT_OUT\
$PR_NO_COLOUR '
RPROMPT=' $PR_RED$PR_SHIFT_IN$PR_HBAR$PR_BLUE$PR_HBAR$PR_SHIFT_OUT\
($PR_YELLOW%D{%a,%b%d}$PR_BLUE)$PR_SHIFT_IN$PR_HBAR$PR_RED$PR_LRCORNER$PR_SHIFT_OUT$PR_NO_COLOUR'
PS2='$PR_RED$PR_SHIFT_IN$PR_HBAR$PR_SHIFT_OUT\
$PR_BLUE$PR_SHIFT_IN$PR_HBAR$PR_SHIFT_OUT(\
$PR_LIGHT_GREEN%_$PR_BLUE)$PR_SHIFT_IN$PR_HBAR$PR_SHIFT_OUT\
$PR_RED$PR_SHIFT_IN$PR_HBAR$PR_SHIFT_OUT$PR_NO_COLOUR '
}
setprompt
[/UPDATE]
ZLE-Widgets
Der Z-Line-Editor (ZLE) ist quasi die Eingabezeile in der zsh. Dafür kann man sich kleine Programme schreiben, die einem das Leben vereinfachen. Ein Beispiel wäre ein Programm, dass bei der Eingabe von ...
diese zu ../..
umwandelt. Jeder weitere Punkt wird wieder umgewandelt. So kann man recht einfach folgendes eingeben:
Auf dem Bildschirm erscheint jedoch folgendes:
Dieses Widget ist kein Standard bei der Z-Shell. Man kann es aber durch folgenden Code in der Konfigurationsdatei ~/.zshrc
erzeugen:
rationalise-dot() {
if [[ $LBUFFER = *.. ]]; then
LBUFFER+=/..
else
LBUFFER+=.
fi
}
zle -N rationalise-dot
bindkey . rationalise-dot
Automatisches tee-ing
In der Z-Shell kann man die Ausgabe eines Kommandos recht einfach in mehrere verschiedene Dateien umleiten. Statt wie in der Bash
ls | tee -a all | tee actual
zu schreiben, kann man in der zsh einfach
eingeben. Beide Befehle führen ls aus und hängen die Ausgabe an die Datei all
an und schreiben sie in die Datei actual
wobei der inhalt jeweils überschrieben wird.
Möchte man die Ausgabe wie beim original tee
Befehl auch auf dem Bildschirm sehen, so leitet man sie auch noch auf STDOUT um:
Verzeichnisse durch Ersetzung wechseln
Ein Beispiel sollte dies am besten Erklären. Man nehme an man hat zwei Verzeichnisse: ~/developement/scripting/perl/modules
und ~/developement/scripting/python/modules
und man befindet sich in ~/developement/scripting/perl/modules
, so kann man durch den Befehl
in das Verzeichnis ~/developement/scripting/python/modules
wechseln. Bei einem cd
Kommando mit zwei Parametern wird im aktuellen Verzeichnis-String das erste Wort durch das zweite ersetzt. Hier also perl
durch python
.
Fazit
Ich bin jetzt nicht 100% sicher, dass alles hier beschriebene nicht auch in der Bash möglich ist. Es zeigt aber auf jeden Fall, dass die Z-Shell jede Menge interessante Möglichkeiten bietet und man viele Dinge einfacher und schneller erledigen kann als in der Bash. Die oben gezeigten Features sind meist nur angerissen und nur eine kleine Auswahl von dem was die Z-Shell bietet. Darüber hinaus besitzt die Z-Shell eine ganze Reihe Module z.B. für Matheoperationen oder einen eigenen FTP-Client, die man bei Bedarf laden kann.
Sehr schön ist auch die Möglichkeit den Screen-Title von der zsh aus zu setzen.
Es lohnt sich auf jeden Fall, diese Shell etwas genauer zu betrachten. Bei mir hat sie mittlerweile die Bash fast vollständig ersetzt (vorhandene Scripte habe ich nicht umgeschrieben).
Links