Die Zsh ist einfach cool. Schon jahrelang beherrscht sie Funktionen, die erst im Laufe der Zeit bei der Bash eingebaut wurden (z. B. gute Tabcompletion). Daher bin ich schon Mitte der 2000er zur Zsh gewechselt und bisher hat mich keine andere Shell zum Wechseln überzeugen können.

Neben der interaktiven Arbeit mit der Zsh ist mein größter Schatz meine ~/.zshrc (und ~/.zshenv und ~/.zhistfile), in der viele Einstellungen zur Erleichterung der täglichen Arbeit liegen.

Alias

Mit dem Befehl alias kann man sich Abkürzungen für Befehle definieren. Oft lässt sich das Verhalten von Befehlen mit Kommandozeilenoptionen verändern. Hier ein paar einfache Beispiele:

alias ffmpeg='ffmpeg -hide_banner'
alias agu='apt update'
alias search='apt-cache search
alias supernice='ionice -c 3 chrt --batch 0 choom -n 1000 -- nice'

Aliase müssen aber keine reinen Befehle seien, sondern auch nur Teile des Anfangs einer Befehlszeile. Somit kann man Variablendefinitionen für diesen einen Befehl voranstellen.

Die Aliase können auch geschachtelt werden und auf andere Aliase zurückgreifen.

alias c='RUST_BACKTRACE=short CARGO_TERM_COLOR=always cargo'
alias LCC='LC_ALL=C.UTF-8'
alias strace='LCC strace -fvttTy'
alias make="supernice make -j$(nproc --ignore 1)"

Außerdem kann man bei der Definition der Aliase auch Shellcode für eine Differenzierung verwenden. So nutze ich die selbe Datei für Root und meinen Benutzer bzw. unterscheide ich an einigen Stellen je nach Hostname oder anderen Kriterien:

if  $USERNAME == root 
then
    alias rm='rm -i --one-file-system'
else
    alias rm='rm --one-file-system'
fi

case $OSTYPE in
  Darwin) alias ls='ls -AGhx';;
  SunOS|OSF1) alias ls='ls -Ahx';;
  *) alias ls='ls --color=auto -Ahx';;
esac

if  $osrelease == debian.8 
then
    alias j='SYSTEMD_LESS=$LESS LCC journalctl'
else
    alias j='SYSTEMD_LESS=$LESS LCC journalctl --no-hostname'
fi

Eine Besonderheit der Zsh sind globale Aliase. Diese werden nicht nur am Anfang, sondern überall in der Eingabe ersetzt. Daher sollte man damit vorsichtig umgehen, aber man kann sich so schöne Helferlein schaffen, die sehr viel Tipparbeit ersparen.

alias -g 1DN='>/dev/null'
alias -g 2DN='2>/dev/null'
alias -g DN='1DN 2DN'

alias -g CG='2>&1 |noglob grep --color=always'
alias -g G='2>&1 |noglob grep'
alias -g L='2>&1 |less'

Somit lassen sich Ausgaben mit cat datei DN leicht unterdrücken oder mit cat datei CG begriff L filtern.

Zurückstellen und aktuelle Hilfe

Mit Alt-q kann man jederzeit die aktuelle Eingabe zurückstellen, einen neuen Befehl eingeben und ausführen und bekommt danach die zurückstellte Eingabe wieder. Dieser Mechanismus wurde mit Alt-h dazu kombiniert, dass für den aktuellen Befehl die Hilfe (Manualpage) aufgerufen wird. Bei einigen Befehlen sind jedoch die Manualpages nicht hilfreich, aber man kann sich selbst Funktionen run-help-BEFEHL definieren, die für BEFEHL die passende Hilfe anzeigen:

run-help-adb()
{
    adb help 2>&1 |less
}

run-help-openssl()
{
    # die Unterprogramme sind in eigenen Manualpages beschrieben; z.B. x509(1)
    man ${1:-openssl}
}

run-help-perf()
{
    # die Unterprogramme sind in eigenen Manualpages beschrieben; z.B. perf-stat(1)
    man perf${1:+-$1}
}

Bearbeitung des letzten Befehls

Manchmal führt man auch Befehlsfolgen aus, die sich im Grunde nur an einer Stelle unterscheiden. Bei der Zsh wurde die !‐Auswertung noch erweitert. Mit !! lässt sich immer der letzte Befehl wiederholen und mit ^1^2 kann man das erste 1 durch 2 ersetzen. Wenn dies an mehreren Stellen passieren soll, muss man ^1^2^:G eingeben.

Um die aktuelle Eingabe zu bearbeiten, verwende ich die Funktionen replace-string und replace-pattern. Diese habe ich an keine Tastenkombination gebunden, sondern nutze den Funktionsaufruf mit Alt-x. In der Konfigurationsdatei müssen die Funktionen mit folgenden Befehlen bekannt gemacht werden:

autoload replace-string
zle -N replace-string
zle -N replace-pattern replace-string

Nächster Befehl anhand der Historie

Neben der Konfiguration in der ~/.zshrc zählt die Historie der Eingaben zu den größten Schätzen. Ich habe diese auch mit der Einstellung SAVEHIST=5000 auf 5000 Einträge vergrößert, sodass ich auf einen reichhaltigen Fundus zugreifen kann. Mit den Einstellungen setopt append_history extended_history hist_expire_dups_first hist_find_no_dups hist_ignore_all_dups hist_save_no_dups lässt sich auch beim Speichern die Historie bereinigen und mit Zusatzinformationen über den Aufrufzeitpunkt (extended_history) ergänzen.

Auf diese Weise kann ich mit Strg-r in der Historie einen Befehl suchen und ausführen. Auf diese Weise habe ich kleine Skripte abgelegt, die ich recht häufig nutze. Mit Strg-o kann man automatisch den nächsten Befehl aus der Historie zur Vorlage bringen.

Teile aus den vorherigen Eingaben holen

Oft nutzt man in neuen Eingaben Teile, insbesondere den letzten, der vorherigen Eingabe. Mit Alt-. kann man sehr schnell darauf das letzte Argument zugreifen. Durch wiederholtes Drücken kann man durch auf die vorherigen Eingaben zugreifen und mit einem Prefix-Argument (Alt-1Alt-9) eine andere Position als die letzte Wählen.

Alternativ kann man auch dafür die !-Ausdrücke verwenden: !-3:4* sind alle Argumente ab dem vierten von der drittvorletzten Eingabe. Oder einfach !$ für das letzte Argument der letzten Eingabe. Mit !* erhält man die letzte Eingabe ohne das erste Wort, womit sich leicht less … gefolgt von rm !* eingeben lässt.

Ressourcenverbrauch von Befehlen

Ähnlich wie die Slow-Queries bei Datenbanken kann man sich auch von der Zsh Informationen zu Befehlen anzeigen lassen, die viel CPU-Zeit verbraucht haben. Wenn ein Befehl länger als zwei Sekunden läuft wird danach eine Auswertung des Ressourcenverbrauchs angezeigt: System- und Prozessanteil, RAM-Verbrauch, Page-Faults, Context-Switches.

REPORTTIME=2
TIMEFMT='%J  usr %U sys %S tot %*E %MMB pf %F %R cs %w %c'