Expect Scripting

Im Alltag eines Shell-Benutzers ist man oft mit interaktiven Shell-Programmen konfrontiert. Will man diese automatisieren, kann man standardmäßig interaktive Eingaben per Kommandozeilenoption übergeben. Im Falle von ssh kann man die Passwortabfrage umgehen, indem man passphraseless authentication nutzt. Doch im Falle von passwd z.B. muss man sich anders weiterhelfen. Hier kommt Expect ins Spiel.

Expect ist eine Skriptsprache zum Automatisieren interaktiver Shell-Programme. Es gibt Implementierung für diverse Programmiersprachen, z.B. Tcl, PERL, Python oder Java.

Beispiel: passwd

Anmerkung: Dieses Beispiel ist als Helloworldbeispiel zu verstehen. Es gibt sichere Möglichkeiten, passwd zu automatisieren. Z.B. mit chpasswd

Im Folgenden soll passwd "automatisiert" werden. Dazu erstellen wir ein Expect-Skript autopasswd mit der Befehlssyntax:
:~/# autopasswd username password

Eine einfache Version ohne Fehlerfallbehandlung könnte so aussehen:

 1 #!/bin/expect
 2 # wrapper to make passwd(1) be non-interactive
 3 # username is passed as 1st arg, passwd as 2nd
 4
 5 set password [lindex $argv 1]
 6 spawn passwd [lindex $argv 0]
 7 expect "assword: $"
 8 send -- "$password\r"
 9 expect "assword: $"
10 send -- "$password\r"
11 expect eof

Zeile 5 definiert und initialisiert die Variable password mit dem übergebenen Passwort. Zeile 6 ruft nun das interaktive passwd auf mit dem übergebenen Username, sodass Expect Kontrolle über Ein- und Ausgabe hat. Zeile 7-10 warten jeweils auf einen bestimmten String und reagieren dann mit der Eingabe des Passworts auf STDIN (Standardeingabe). Zeile 11 ist optional, beendet das Skript aber explizit und sauber.

Der Beispielcode ist wirklich nur eine sehr einfache Variante. Prinzipiell lassen sich auch komplexere Interaktionspfade mit if, switch und Schleifenstatements implementieren. Auch die Fehlerabhandlung sollte man nicht vergessen.

Anmerkung/Bug

Unter Debian (Das einzige System, auf dem ich getestet habe wink ) gibt es eine Besonderheit bzw. einen Bug (imo Ansichtssache). passwd erwartet nach der Ausgabe von Enter new UNIX password: nicht unmittelbar eine Eingabe, sondern erst ein paar Millisekunden verzögert. Dies macht für den Menschen keinen Unterschied, für eine Expect-Skript aber schon. Daher folgende Abänderung in Zeilen 8 und 11:

 1 #!/bin/expect
 2 # wrapper to make passwd(1) be non-interactive
 3 # username is passed as 1st arg, passwd as 2nd
 4
 5 set password [lindex $argv 1]
 6 spawn passwd [lindex $argv 0]
 7 expect "assword: $"
 8 sleep .1
 9 send -- "$password\r"
10 expect "assword: $"
11 sleep .1 
12 send -- "$password\r"
13 expect eof

autoexpect

Ohne dieses Features zu dokumentieren, möchte ich auf dessen Existenz hinweisen. Mit autoexpect lassen sich Interaktionen mit einem Shell-Programm aufzeichnen. So generierte Expect-Skripte können viel Arbeit ersparen.

Links/Installation

  • Im Debian das Paket expect (enthält kein autoexpect) oder expect-tcl8.3 (enthält autoexpect) installieren.
  • Projekthomepage: http://expect.nist.gov/

-- DennisKlein - 22 Jan 2009
Topic revision: r2 - 2009-02-23, DennisKlein