Session-Management mit »screen«
Inhalt
1. Einleitung
»screen« ist ein kleines Programm, das es ermöglicht, mehrere Sitzungen (Sessions) von einem einzigen Terminal laufen zu lassen. Es baut zu jeder Session ein virtuelles Fenster auf und verbindet sie zu einem tty. Die Session kann auch gänzlich vom Terminal getrennt werden (detach).
Im Zeitalter von grafischen Oberflächen ist es nicht mehr so interessant zwischen verschiedenen Sitzungen innerhalb
eines Terminals wechseln zu können - das Starten eines zweiten Terminalfensters (xterm, putty, ...) tut
es auch. Darum soll es in diesem Artikel daher auch gar nicht gehen. Vielmehr soll ein Session Management mit Hilfe
von »screen« aufgebaut werden.
2. »screen« installieren
Wer Linux nutzt, wird screen im Allgemeinen bereits vorfinden und es nicht installieren müssen. Falls es doch nicht installiert ist, findet sich ein Paket »screen« sicher auf der CD.
Bei proprietären Unix-Derivaten sieht die Sache anders aus, hier muss screen möglicherweise aus fremden Quellen installiert werden. Bei fehlender root-Berechtigung können Sie screen auch in Ihrem Heimatverzeichnis installieren. Dies soll am Beispiel AIX 5.3 exemplarisch durchgeführt werden:
Unter aixpdslib.seas.ucla.edu/packages/screen.html habe ich mir die entsprechende Version heruntergeladen und in meinem Heimatverzeichnis entpackt:
$ cd $ uncompress -c screen.4.0.2.tar.Z | tar xf - $ mv usr/local/* . $ rmdir usr/local $ rmdir usr
screen findet sich nun unter ~/bin/screen.
Update:
Der Server »aixpdslib.seas.ucla.edu« scheint seit einiger Zeit tot zu sein. Als Alternative lässt sich auch das
Paket gnu.screen-3.9.8.0 von Bull ins Heimatverzeichnis entpacken:
$ cd $ chmod +x gnu.screen-3.9.8.0.exe $ ./gnu.screen-3.9.8.0.exe inflating: gnu.screen-3.9.8.0.bff inflating: gnu.screen-3.9.8.0.bff.asc $ restore -xvqf gnu.screen-3.9.8.0.bff $ mv usr/local/* . $ rm -rf ./usr
Damit die von Bull kompilierte Version von screen aus dem Heimatverzeichnis heraus funktioniert, ist noch ein bisschen zusätzliche Handarbeit notwendig. Zunächst muss die Konfigurationsdatei aus dem Verzeichnis lib/screen-3.9/etc ins Heimatverzeichnis kopiert werden:
$ cp ~/lib/screen-3.9/etc/screenrc ~/.screenrc
Dann müssen ein paar Umgebungsvariablen so gesetzt werden, dass screen nicht versucht in geschützte Verzeichnisse zu schreiben - diese könnte man z.B. in sein lokales Profile eintragen:
export SCREENDIR=$HOME/tmp/screen
Update2:
Auch unter Solaris lässt sich screen im Heimatverzeichnis installieren. Das folgende Beispiel zeigt die Installation für Solaris 9 für Sparc.
Dazu habe ich mir von www.sunfreeware.com die Pakete screen-4.0.2-sol10-sparc-local.gz und ncurses-5.6-sol10-sparc-local.gz (die 10er-Pakete sind auch unter Solaris 9 lauffähig!) heruntergeladen und in meinem Heimatverzeichnis entpackt:
$ cd $HOME $ mkdir .tmp $ gunzip screen-4.0.2-sol10-sparc-local.gz $ pkgtrans screen-4.0.2-sol10-sparc-local $PWD/.tmp The following packages are available: 1 SMCscreen screen (sparc) 4.0.2 Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]: all Transferringpackage instance $ gunzip ncurses-5.6-sol10-sparc-local.gz $ pkgtrans ncurses-5.6-sol10-sparc-local $PWD/.tmp The following packages are available: 1 SMCncurs ncurses (sparc) 5.6 Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]: all Transferring package instance $ cd $HOME/.tmp/SMCscreen/reloc $ tar cpBf - ???* | ( cd $HOME && tar xpBf - ) $ cd $HOME/.tmp/SMCncurs/reloc $ tar cpBf - ???* | ( cd $HOME && tar xpBf - ) $ rm -rf $HOME/.tmp/SMC*
Ein bisschen Nacharbeit ist noch erforderlich - für die Bibliotheken müssen ein paar Links gesetzt werden und das Verzeichnis für die Sockets muss angelegt werden:
$cd $HOME/lib $ln -s libncurses.so.5.6 libncurses.so.5 $cd $HOME/bin $ln -s screen-4.0.2 screen $mkdir -p $HOME/.tmp/screens $chmod 0700 $HOME/.tmp/screens
Zu guter Letzt müssen einige Umgebungsvariablen gesetzt werden, damit screen seine Bibliotheken findet und nicht versucht in geschützte Verzeichnisse zu schreiben - diese könnte man z.B. in sein lokales Profile eintragen:
export LD_LIBRARY_PATH=$HOME/lib export SCREENDIR=$HOME/.tmp/screens export PATH=$PATH:$HOME/bin export SYSSCREENRC=$HOME/etc export TERMINFO=$HOME/share/terminfo
3. Grundlegende Kommandos
Eine neue Session lässt sich mit
screen [Kommando]
starten. Für unsere Zwecke interessant ist der Aufbau einer ssh-Verbindung zu einem entfernten Rechner, also etwa
$ screen ssh barney
Eine so aufgebaute verbindung lässt sich mit der Tasten-Kombination <CRTL-A><D> vom Terminal abkoppeln, ohne dass die Shell dies bemerken würde.
Alle zur Zeit aktiven Sessions lassen sich mit dem Schalter »-list« anzeigen:
$ screen -list There are screens on: 401566.pts-18.darkstar (Detached) 159936.pts-12.darkstar (Attached) 2 Sockets in /tmp/uscreens/S-armin.
Abgekoppelte Sitzungen werden als (Detached) angezeigt. Bei einer größeren Anzahl abgekoppelter Sessions ist es aber schwierig, die richtige aus der Liste zu finden, da man sich kaum PID und tty gemerkt hat (darkstar ist nicht etwa der Name des Systems, zu dem die ssh-Verbindung aufgebaut wurde, sondern der Rechner, auf dem ich »screen« aufgerufen habe - folglich also immer derselbe...)
Deshalb gibt es die Möglichkeit, der Session einen eigenen Namen zu geben, der dann hinter dem PID auftaucht, also etwa...
$ screen -S barney ssh barney ^AD [detached]
$ screen -list There are screens on: 700572.pts-18.darkstar (Detached) 159936.pts-12.darkstar (Attached) 921688.barney (Detached) 3 Sockets in /tmp/uscreens/S-armin.
Nun ist klar, welchen Screen wir gerade in den Hintergund geschickt haben. Mit dem Befehl
$ screen -r barney
wird die Session wieder mit dem Terminal verbunden.
4. Session Management
Mit den unter 3. erworbenen Mitteln wollen wir nun ein Session-Management aufbauen. Dazu erstellen wir drei Skripts. Die Beispiel-Skripts sind ksh-Skripts, sie sind aber kompatibel zur bash gehalten, tauschen Sie lediglich #!/bin/ksh gegen #!/bin/bash aus.
a. bin/screenwrapper
#!/bin/ksh
SESSION_CMD="$1"
shift
SESSION_ARGS="$@"
SESSION_NAME="$(echo $@ | awk '{print $NF}')"
SESSION_TERM=${TERM:-xterm}
screen="$HOME/bin/screen"
if [ -z "SESSION_ARGS" ]
then
$SESSION_CMD
else
case $SESSION_NAME in
-*)
$SESSION_CMD $SESSION_ARGS
;;
?*)
exec "$screen" -T $SESSION_TERM -h 10000 -S "$SESSION_NAME" $SESSION_CMD $SESSION_ARGS
;;
esac
fi
Dieses Skript baut eine Screen Session auf und übergibt das Kommando an die Session, der Name der Session ergibt sich aus dem Argument, also wenn wir
$ screenwrapper ssh homer
eingeben, sehen wir:
$ screen -list There is a screen on: 159936.homer (Attached) 1 Socket in /tmp/uscreens/S-armin
Für "screenwrapper ssh" setzen wir einen Alias in der Initialisierungsdatei für die Shell (z.B. .login für Bourne-Shell und ksh oder .bash_login für die Bash):
alias s='~/bin/screenwrapper ssh'
so dass wir einfach
$ s homer
eingeben können.
b. bin/lsscreens
Als nächstes brauchen wir ein Skript, das die Ausgabe aller laufenden Sitzungen anzeigt. Dies nennen wir z.B. lsscreens:
#!/bin/ksh
screen=$HOME/bin/screen
screens="$($screen -ls | grep tach | sed -e 's/[ ]/#/g')"
if [ -n "$screens" ]
then
printf "\n PID HOST STARTED@ ( STATE )\n"
for screen in $screens
do
pid=$(echo $screen | cut -d . -f1 | cut -d\# -f2)
stm=$(ps uax | egrep -w "$USER[ ]*$pid" | awk '{print $9}')
hst=$(echo $screen | cut -d . -f2 | cut -d\# -f1)
sta=$(echo $screen | cut -d\# -f3)
printf "%8d %-16s %-10s %s\n" $pid $hst $stm $(echo $sta | sed -e "s/\(Detached\)/^[[32m\1^[[0m/")
done
echo
else
printf "\n No screens in use.\n\n"
fi
Die Ausgabe gibt uns einen schnellen Überblick über alle ssh-Sessions, wann sie gestartet wurden und ob sie aktuell in einem Fenster laufen oder vom Terminal abgekoppelt wurden:
$ lsscreens PID HOST STARTED@ ( STATE ) 1110162 akira 10:01:46 (Detached) 671902 homer 10:02:01 (Attached) 1052876 barney 11:27:48 (Attached) 970912 bart 12:53:50 (Detached) 1048698 lisa 13:27:36 (Detached) 188568 bart 12:53:50 (Detached)
c. bin/attach
Screens, die sich im Status Detached befinden, können dann mit dem folgenden Skript, das im Wesentlichen screen -r ausführt, wieder mit einem Terminal verbunden werden:
#!/bin/ksh
screen="$HOME/bin/screen" SCREENARGS='-r' ARGS="" while (($#>0)) do case $1 in -f) SCREENARGS='-r -D' shift ;; *) HOSTNAME=$1 ARGS=$1 shift#must exit here
;; esac done $screen $SCREENARGS $ARGS
So verbinden Sie sich mit
$ attach akira
wieder mit der laufenden Verbindung zu akira. Haben Sie mehrer Sitzungen zum selben Rechner laufen, die sich im Status Detached befinden, würden Sie allerdings folgende Fehlermeldung bekommen:
$ attach bart There are several suitable screens on: 970912.bart (Detached) 188568.bart (Detached) Type "screen [-d] -r [pid.]tty.host" to resume one of them.
In diesem Fall müssen Sie den PID mit übergeben:
$ attach 188568.bart
Eine Verbindung, die in irgendeinem Terminal läuft, sich also im Status Attached befindet, lässt sich zunächst einmal nicht auf ein anderes Terminal bringen, weil sich mit attach bzw. screen -r nur solche Sitzungen an ein Terminal binden lassen, die nicht bereits anderswo verbunden sind. Doch unser Skript hat eine force-Option, die dies dennoch möglich macht:
$ attach -f barney
Nun wird die Session vom anderen Terminal getrennt und zu Ihrem aktuellen Terminal verbunden.
5. Tipps
Wie wir gesehen haben, wird ein Screen mit ^AD in den Hintergrund geschickt. Diese Tastenkombination führt im Zusammenhang mit dem Emacs-Mode von bash, ksh, tcsh oder zsh zu Problemen: Mit ^A springt man hier zum Anfang der Kommandozeile - doch in einer Screen-Session leitet man mit ^A ein Screen-Kommando ein (z.B. eben Detach). Um hier Konflikten zu entgehen, empfiehlt es sich einen anderen Buchstaben zu definieren. Folgendes kann man z.B ans Ende seiner ~/.screenrc setzen:
escape ^gg
Damit würde nun ^G anstelle von ^A ein Screen-Kommando einläuten. Gibt es noch keine Datei .screenrc in Ihrem Heimatverzeichnis, kann dies auch der einzige Eintrag sein.