Wenn ich in der Kommandozeile unterwegs bin, muss ich oft zwischen verschiedenen Verzeichnissen und Verzeichnisebenen wechseln. Das ist umständlich, wenn ich zwischen mehreren Ebenen navigieren muss, und kostet Tipparbeit. Ich würde gerne Abkürzungen für bestimmte Verzeichnisse definieren, in die ich häufig wechseln muss.

Ganz praktisch liegt mein lokales git-Repository, in dem sich dieses Blog befindet, im Verzeichnis ~/code/sites/www.timschroeder.me. Ich muss also jedes Mal, wenn ich in dieses Verzeichnis wechseln will, cd ~/code/sites/www.timschroeder.me eingeben, und die Funktion zum Auto-Vervollständigen von Pfaden in meiner Kommandozeile mit der Tab-Taste hilft mir nur eingeschränkt.

Als ich mir heute vorgenommen habe, das zu vereinfachen, dachte ich zuerst an den Befehl alias, mit dem ich in der Kommandozeile fast beliebig Abkürzungen definieren kann. Ich könnte etwa durch diesen Befehl definieren, dass mich die Eingabe von cdb in mein Blog-Verzeichnis bringen soll:

alias cdb='cd ~/code/sites/www.timschroeder.me'

Wenn ich diese Zeile in die Datei ~/.bashrc aufnehme, steht mir die Abkürzung dauerhaft zur Verfügung. Schon gar nicht schlecht, aber ich will mir keine kryptischen Abkürzungen merken müssen, so wie cdb.

Lieber hätte ich es, wenn ich eine Abkürzung für den Pfad ~/code/sites/www.timschroeder.me definieren könnte. Wenn ich die Abkürzung hätte und sie “blog” nennen würde, könnte ich dann durch die Eingabe von cd blog von überall her in mein Blog-Verzeichnis wechseln. Mit dem alias-Befehl habe ich das nicht geschafft1. Ein paar Experimente mit symbolischen Links, die ich mit ln -s [..] angelegt hatte, funktionierten auch nicht, führten aber dazu, dass ich zwischendurch die lokale Kopie meines Blog-Verzeichnisses gelöscht habe2.

Was will ich tun? Ich habe vor, den Befehl cd so zu ändern, dass das Argument blog durch den Pfad meines Blog-Verzeichnisses ersetzt wird. cd ist ein sogenannter Builtin-Befehl, der von keinem separaten Programm ausgeführt wird, sondern Bestandteil der Shell ist, also in meinem Fall der Bash-Shell. Die “Shell” ist die Kommandozeile, d.h. letztlich ein Programm, das eine Kommandozeile bereitstellt. Davon gibt es mehrere, von denen man sich eine aussuchen kann. Ich benutze die Bash-Shell, die in vielen Linux-Distributionen die Standard-Shell ist.

Ich kann kein Shell-Skript mit dem Namen cd benutzen, um den cd-Befehl umzuleiten, weil Builtins von der Shell vorrangig ausgewertet werden und mein Skript nie ausgeführt würde3. Eine Shell-Funktion würde allerdings funktionieren, weil Shell-Funktionen vorrangig vor Builtins ausgewertet werden4.

Eine Shell-Funktion ist eine Gruppierung von Shell-Befehlen, die ich über den Namen der Funktion aufrufen und somit ausführen kann. Ich kann Shell-Funktionen in Shell-Skripten einsetzen, aber auch unabhängig davon verwenden. Ich kann eine Shell-Funktion etwa in der ~/.bashrc-Datei definieren. Die Funktion steht dann in der Shell zur Verfügung und würde Builtin-Befehle “verdrängen”.

Ich benötige also eine Shell-Funktion, die den cd-Befehl “abfängt” und die Abkürzung blog durch mein Blog-Verzeichnis ersetzt. In allen übrigen Fällen soll die Shell-Funktion den cd-Befehl wie üblich ausführen. Das sieht in der einigermaßen kryptischen Bash-Syntax so aus:

cd() {
    if [[ $1 == "blog" ]]; then
        cd ~/code/sites/www.timschroeder.me
    else
        command cd "$@"
    fi
}

In einer Zeile zusammengefasst ergänze ich dies in ~/.bashrc:

cd() { if [[ $1 == "blog" ]]; then cd ~/code/sites/www.timschroeder.me; else command cd "$@"; fi }

Jetzt kann ich in der Kommandozeile mit cd blog von jedem Verzeichnis aus in mein Blog-Verzeichnis wechseln. Dieser Ansatz hat den Nachteil, dass ich dann, wenn ich mich in einem Verzeichnis befinde, das ein Unterverzeichnis “blog” hat, nicht mehr mit cd blog in dieses Unterverzeichnis wechseln kann. Stattdessen müsste ich cd ./blog eingeben.

  1. Die Dokumentation der Bash-Shell sagt denn auch, dass das nicht geht: “There is no mechanism for using arguments in the replacement text”. 

  2. Dank git war es kein Problem, den aktuellen Stand meines Blogs vom entfernten Git-Server mit git clone [..] wiederherzustellen. 

  3. Newham, Rosenblatt, Learning the bash shell, 3. Auflage 2009, S. 84. 

  4. Ibid.