Multi Tasker (Linux-Magazin, Juni 2013)

Statt die Fenster einer Entwicklungsumgebung manuell zurechtzuzupfen, kann der Terminal-Multiplexer tmux sie aus Konfigurationsdateien restaurieren.

Wer keine Entwicklungsumgebung wie Eclipse zum Programmieren nutzt, sondern viel auf der Kommandozeile eines Terminalfensters tippt, dem ist sicher screen nicht fremd, eine uralte und in Insiderkreisen wohlbekannte Terminal-Utility. Sie stellt unter anderem sicher, dass man eine wegen eines Netzwerkproblems abgebrochene ssh-Session später genau dort problemlos fortsetzen kann wo man aufgehört hat zu tippen. Dabei stellt screen sich zwischen Anwender und im Terminal ablaufenden Applikationen und gaukelt letzteren deswegen immer noch aufmerksame User vor, auch wenn diese schon längst ins Wochenende abgezischt sind.

Zahn der Zeit

In den vergangenen zwanzig Jahren ist nun die Unix-Welt nicht stehen geblieben und das Projekt tmux hat sich vor einiger Zeit angeschickt, screen zu verbessern und abzulösen. Wie screen bietet tmux dem User verschiedene Sessions, die wiederum aus "Windows" bestehen, was im Screen-Jargon keine Desktop-Fenster, sondern im gleichen Terminalfenster umschaltbare Textoberflächen sind. Mit Tastatur-Shortcuts unterteilt tmux diese Fenster bei Bedarf noch weiter in vertikal oder horizontal angeordnete "Panes", die alle gleichzeitig sichtbar sind (Abbildung 1).

Abbildung 1: Zwei tmux-Kommandos teilen das Window erst in zwei horizontale Panes, und die rechte Pane anschließend in zwei vertikale.

Server und Client

Ein automatisch gestarteter tmux-Server behält dabei den Überblick über alle aktiven Sessions und der User kann diese von der Kommandozeile aus fernsteuern. Mittels tmux-Kommandos lassen sich so neue Sessions anlegen oder zerstören, Fenster hinzufügen oder löschen, und Panes ein- und ausbauen, vergrößern oder verkleinern. So bietet es sich an, Entwicklungsumgebungen mit mehreren Windows und Panes als Konfiguration im Source-Code-Repository abzuspeichern und bei Bedarf mit einem einzigen Kommando abzurufen und anzuzeigen. Tmux kann in den Panes auch Applikationen wie den Lieblingseditor starten, der gleich eine Projektdatei lädt. Eine andere Pane startet vielleicht schon mal die Testsuite, und eine dritte zeigt mit tail die letzten Zeilen einer Logdatei an.

Tmux läuft auf allen gängigen Plattformen, wer also mal auf einem Linux Desktop und unterwegs auf einem Macbook arbeitet, findet in beiden Umgebungen die gleichen Windows und Panes vor.

Anpassen erwünscht

Tmux kommt von Haus aus mit völlig unmöglichen Tastaturkombinationen daher. Um in einer Tmux-Session nicht die laufende Applikation wie den Editor anzusteuern, sondern den zwischengeschalteten Terminal-Multiplexer, tippt der User den sogenannten Prefix. In einer jungfräulich belassenen Tmux-Installation ist dafür Ctrl-B eingestellt, aber das verursacht nicht nur Sehnenscheidentzündungen beim Tippen sondern ist auch ein gängiges aber damit geblocktes vi-Kommando.

Glücklicherweise erlaubt es Tmux, alles umstellen, und so stückelt jeder Nutzer im Vollbesitz seiner geistigen Kräfte sofort nach der Installation seine eigene .tmux.conf-Datei zusammen. Meine eigene ist auf [4] und besteht letztendlich nur auf allgemeinen Empfehlungen, wie den Prefix auf Ctrl-A zu stellen (genau wie in screen) und den Rest auf vim-ähnliche Kombinationen (h=links j=abwärts k=aufwärts l=rechts). So braucht man zum wechseln zwischen den Panes keine Emacs-ähnlichen Textkommandos anzugeben, sondern springt mit Prefix-Ctrl-h zum Beispiel in die Pane linker Hand.

Babylonische Dialekte

Das Anpassen der Shortcuts bringt natürlich gewissen Nachteile mit sich, wie zum Beispiel, dass jeder einen anderen tmux-Dialekt versteht und in fremden Umgebungen hilflos zappelt wie eine Schildkröte auf dem Rücken. Jederzeit versteht Tmux aber ausgeschriebene Kommandos, die Tmux auf die Tastenkombination Prefix-: (Prefix gefolgt von einem Doppelpunkt) auf der Statuszeile entgegennimmt. Die gleichen Kommandos akzeptiert tmux auf der Kommandozeile, so dass zusammengezimmerte Skripts zum Aufsetzen einer Fenstergruppe global gültig sind. So setzt das Perl-Skript in Listing 1 in Zeile 19 den Befehl "tmux kill-session" mit dem Namen der Session ("log4perl") ab, falls der User es mit der Option -k aufgerufen hat. Der Befehl nimmt Verbindung vom Tmux-Server auf (falls dieser läuft), fragt nach der Session und lässt sie zusammenfalten.

Listing 1: tmux-setup

    01 #!/usr/local/bin/perl -w
    02 use strict;
    03 use Sysadm::Install qw( tap cd sysrun );
    04 use Log::Log4perl qw(:easy);
    05 use Getopt::Std;
    06 sub tmux; # declare as function
    07 
    08 my($home)   = glob "~";
    09 my $session = "log4perl";
    10 
    11 getopts "vk", \my %opts;
    12 
    13 my $loglevel = $INFO;
    14 $loglevel = $DEBUG if $opts{ v };
    15 
    16 Log::Log4perl->easy_init( $loglevel );
    17 
    18 if( $opts{ k } ) {
    19   tmux "kill-session", "-t", $session;
    20   exit 0;
    21 }
    22 
    23 tmux "source", "$home/.tmux.conf";
    24 
    25 if( 0 == system "tmux", "has-session", 
    26               "-t", $session ) {
    27   DEBUG "Session $session already exists";
    28 } else {
    29   DEBUG "Creating session $session";
    30   tmux "new-session", "-s", $session, 
    31         "-d";
    32   tmux "split-window", "-h";
    33   tmux "split-window", "-v";
    34   tmux "send-keys", "-t", "$session:0.0",
    35   "vim -p `find . -name '*.pm' | head -2`",
    36     "C-m";
    37   tmux "send-keys", "-t", "$session:0.1", 
    38        "perl Makefile.PL; make test", "C-m";
    39   tmux "send-keys", "-t", "$session:0.2",
    40        "vim t/*.t", "C-m";
    41 }
    42 
    43 tmux "attach", "-t", $session;
    44 
    45 ###########################################
    46 sub tmux {
    47 ###########################################
    48   my( $stdout, $stderr, $rc ) = 
    49      tap "tmux", @_;
    50 
    51   return $rc;
    52 }

Nur einmal

Die Option -v (verbose) veranlasst Listing 1 dazu, die Log4perl-Konfiguration auf den Loglevel $DEBUG zu stellen, während es sonst mit $INFO weit weniger geschwätzig ist. Damit das Skript nicht jedes Tmux-Kommando ausschreiben muss, ruft die Funktion tmux() ab Zeile 46 das Kommando tmux über die Shell auf. Die Funktion tap() aus dem CPAN-Modul Sysadm::Install leitet dies in die Wege. Damit die Klammern bei den Aufrufen von tmux() wegfallen können, deklariert Zeile 6 sie als Funktion im aktuellen Namespace.

Zeile 23 liest mit source die Konfigurationsdatei .tmux.conf im Home-Verzeichnis des Users ein. Eigentlich sollte tmux dies automatisch tun, doch die beim Testen verwendete Version tat dies nicht -- wohl ein Bug.

Des weiteren prüft es in Zeile 25 mit dem Befehl "tmux has-session" ob die aufzusetzende Tmux-Session vielleicht schon läuft, und fällt durch bis zum Befehl "attach" in Zeile 43, falls die Session schon steht, um sich nur noch damit zu verbinden.

Falls die Session noch nicht bekannt ist, erzeugt der Befehl new-session in Zeile 30 eine neue mit dem Namen "log4perl". Der Name der Session verweist auf das Log4perl-Projekt, in dessen Git-Repository sie als Entwicklungsumgebung dient. Der Parameter -d ("detach") am Schluss des Tmux-Kommandos bestimmt, dass das Skript nicht sofort in die Session hineinspringt und die GUI darstellt, sondern brav bis zum Befehl attach in Zeile 43 Ende rattert, bevor der User etwas sieht.

Fenster, spalte dich

Die split-window-Anweisungen ab Zeile 32 mit den Optionen -h (horizontal) und -v (vertical) erzeugen zusätzliche Panes im Window, indem sie es einmal horizontal und einmal vertikal teilen. Windows und Panes numeriert Tmux von 0 her durch (aber Vorsicht, eine oft genutzte Konfigurationsoption stellt dies auf 1 um). Um also bei einem jungfräulichen Tmux die zweite Pane im ersten Window der Session "log4perl" zu adressieren, notiert Zeile 37 log4perl:0.1 und gibt mit send-keys das Kommando zum Ablaufen der Testsuite mit einem abschließenden C-m (Return) an. Genauso könnte man aber mit vagrant ssh schon mal in eine Vagrant-VM wechseln, wie im letzten Snapshot besprochen, um sicher zu stellen, dass die Testsuite auch im staubfreien Reinraum abläuft. Zeile 35 findet die ersten zwei .pm-Dateien in der Hierarchie des gewählten Perl-Projekts und übergibt ihre Namen dem Editor vim mit der Option -p, der sie in sogenannten Tabs in der Pane auf der linke Seite anzeigt (Abbildung 2).

Abbildung 2: Ein Tmux-Window mit Editor, Test Suite, und Testdatei.

Installation

Tmux ist in den Repositories gängiger Repositories vorhanden, unter Ubuntu führt

    sudo apt-get install tmux

direkt zum Ziel. Allerdings hat sich das Projekt in letzter Zeit stetig weiter entwickelt und man sollte mindestens Version 1.7, wenn nicht gar 1.8 verwenden, um auch nur in den Genuss aller in diesem Artikel vorgestellten Features zu kommen. Tüftler können den Source-Code direkt von [2] herunterladen und kompilieren. Als Abhängigkeiten sind nur libevent (mindestens 1.4.14 oder 2.0) und ncurses notwendig. Das Skript auf [5] erledigt die Kompilationsschritte automatisch.

Im Tmux-Buch [3] gibt ein erfahrener Anwender nützlicher Tipps zum Bewältigen gängiger Aufgaben mit Tmux, von Entwicklungsumgebungen bis zum Pair-Programming, bei dem zwei Entwickler örtlich getrennt gleichzeitig in der gleiche Session in unterschiedlichen Panes tippen. Und das Beste: Ins Source-Control-System eingecheckt kann auch der nächste Entwickler sofort die Tool-Umgebung aufsetzen und verzögerungsfrei produktiv mitarbeiten.

Infos

[1]

Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2013/06/Perl

[2]

Projektseite des Tmux-Projektes: http://tmux.sourceforge.net/

[3]

Hogan, Brian: tmux: Productive Mouse-Free Development, Pragmatic Bookshelf, 2012

[4]

Michael Schillis Tmux-Konfiguration: http://github.com/mschilli/dotfiles/.tmux.conf

[5]

Skript zum statischen Kompilieren von Tmux auf schwierigen Plattformen: https://gist.github.com/ryin/3106801

[6]

CPAN-Modul Debug::Fork::Tmux Debugger-Fenster mit Tmux

Michael Schilli

arbeitet als Software-Engineer bei Yahoo in Sunnyvale, Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen der Skriptsprache Perl. Unter mschilli@perlmeister.com beantwortet er gerne Ihre Fragen.