Expect je rozšíření skriptovacího jazyka Tcl určené pro automatizaci práce s programy, které interaktivně používají rozhraní příkazového řádku. Expect vytvořil v roce 1990 Don Libes pro unixové systémy, ale od té doby byl přenesen i na Microsoft Windows a jiné systémy.
Úvod Expect se používá pro automatizaci řízení interaktivních aplikací, jako je telnet, FTP, passwd, fsck, rlogin, tip, SSH a dalších. Expect používá pseudoterminály v Unixu nebo emulaci konzole ve Windows pro spuštění požadovaného programu, se kterým pak komunikuje pomocí terminálu nebo konzolového rozhraní podobně jako by to dělal člověk. Výsledkem může být úplná automatizace činnosti nebo například poskytnutí grafického uživatelského rozhraní uživateli (při použití Tk).
Expect disponuje mechanismem regulárních výrazů pro vyhledávání vzorků a obecnou programovou funkcionalitou, která umožňuje jednoduchým skriptům inteligentně řídit programy, které nemají programovací jazyk, makra nebo jiný mechanismus pro programování.
Použití Expect slouží jako „lepidlo“ umožňující propojit dohromady existující programy, které nebyly navrženy, aby vzájemně spolupracovaly. Obecně je vhodné využít co nejvíce funkcionality existujících nástrojů, než řešit problémy v Expectu.
Důležitou doménou pro Expect jsou komerční softwarové produkty. Mnoho programů poskytuje ovládání pomocí příkazového řádku, ale často neumožňují psaní skriptů. Byly navrženy, aby umožňovaly správu určitého zařízení, ale výrobce často nevynaložil dostatek prostředků na plnou implementaci robustního skriptovacího jazyka. Skript v Expectu může spustit shell, používat proměnné prostředí, provádět některé unixové příkazy pro načtení dalších informací a pak vstoupit do prostředí příkazového řádku programu s nezbytnými informacemi pro dosážení záměru uživatele. Po shromáždění potřebných informací v příkazovém řádku programu může skript provést inteligentní rozhodnutí o tom, zda provést nějakou akci, a jak.
Pokaždé, když Expect dokončí operaci, jsou výsledky uloženy do lokální proměnné $expect_out. To skriptu umožňuje shromáždit informace potřebné pro uživatele, a zároveň rozhodnout o dalším chování skriptu.
Expect se často používá pro vytváření testů programů, utilit nebo vestavěných systémů. Příkladem testovacího nástroje napsaného v Expectu je DejaGnu, který byl intenzivně používán pro testování GCC, a je velmi vhodný i pro testování na vzdálených strojích například při vývoji vestavěných systémů.
Pro automatizaci vytváření expect skriptů lze použít nástroj nazývaný autoexpect, který sleduje činnost uživatele a pomocí heuristik vytváří skript v expectu. Přestože vygenerovaný kód může být rozsáhlý a hůře srozumitelný, lze se jím inspirovat nebo jej upravit na lepší kód.
# Proměnné $remote_server, $my_user_id, $my_password a $my_command musí být # již nastaveny dříve ve skriptu. # Otevřít spojení telnetem na server, a počkat na výzvu k zadání uživatelského jména spawn telnet $remote_server expect "username:" # Poslat uživatelské jméno a čekat na výzvu na zadání hesla send "$my_user_id\r" expect "password:" # Poslat heslo a čekat na výzvu shellu send "$my_password\r" expect "%" # Poslat požadovaný příkaz a znovu čekat na výzvu shellu send "$my_command\r" expect "%" # Výsledky uložit do proměnné results pro pozdější zobrazení nebo uložení do souboru set results $expect_out(buffer) # Ukončit telnetové spojení a čekat na ukončení vstupu send "exit\r" expect eof
Dalším příkladem je skript, který automatizuje FTP:
# Nastavte parametr timeout (prodleva) na vhodnou hodnotu; # pokud je např. soubor velmi velký a síť pomalá, je třeba # hodnotu parametru dobře vyladit. set timeout -1 # Otevřít ftp spojení na server a počkat na výzvu k zadání uživatelského jména spawn ftp $remote_server expect "username:" # Poslat uživatelské jméno a čekat na výzvu na zadání hesla send "$my_user_id\r" expect "password:" # Poslat heslo a čekat na výzvu programu FTP send "$my_password\r" expect "ftp>" # Přepnout to binárního režimu a počkat na výzvu programu FTP send "bin\r" expect "ftp>" # Vypnout vypisování dotazů send "prompt\r" expect "ftp>" # Načíst všechny soubory send "mget *\r" expect "ftp>" # Ukončit FTP spojení a čekat na ukončení vstupu send "bye\r" expect eof
Následuje příklad, který ukazuje automatizaci použití SFTP (s heslem):
#!/usr/bin/env expect -f
# procedura pro připojení; výsledek je 0 při úspěchu, 1 jinak proc connect {passw} { expect { "Password:" { send "$passw\r" expect { "sftp*" { return 0
# timed out return 1 }
# načti vstupní parametry set user [lindex $argv 0] set passw [lindex $argv 1] set host [lindex $argv 2] set location [lindex $argv 3] set file1 [lindex $argv 4] set file2 [lindex $argv 5]
#puts "Argument data:\n"; #puts "user: $user"; #puts "passw: $passw"; #puts "host: $host"; #puts "location: $location"; #puts "file1: $file1"; #puts "file2: $file2";
# kontrola, jestli máme všechno if { $user == "" || $passw == "" || $host == "" || $location == "" || $file1 == "" || $file2 == "" } { puts "Usage: <user> <passw> <host> <location> <file1 to send> <file2 to send>\n" exit 1 }
#sftp to specified host and send the files spawn sftp $user@$host
set rez [connect $passw] if { $rez == 0 } { send "cd $location\r" set timeout -1 send "put $file2\r" send "put $file1\r" send "ls -l\r" send "quit\r" expect eof exit 0 } puts "\nError connecting to server: $host, user: $user and password: $passw!\n" exit 1
Předávání hesel jako pomocí parametrů příkazů použité v tomto příkladě, je bezpečnostní díra, protože jiní uživatelé na stejném počítači mohou heslo zjistit pomocí příkazu ps. Je však možné kód upravit, aby poslal heslo po vypsání výzvy:
stty -echo send_user -- "Enter Password: " expect_user -re "(.*)\n" send_user "\n" stty echo set PASS $expect_out(1,string)
Tento postup je bezpečnější, ale stále je problémem uložení nezašifrovaného hesla v textu skriptu.
Další příkladem je automatizované přihlášení uživatele na počítač pomocí ssh:
# timeout is a předdefinovaná proměnná v expectu nastavená na 10 sec # spawn_id je další implicitně používaná proměnná v expectu. set timeout 60 spawn ssh $user@machine while {1} { expect {
eof {break} "The authenticity of host" {send "yes\r"} "password:" {send "$password\r"} "*\]" {send "exit\r"}
wait # Je vhodné zavřít spawn_id handle vytvořené příkazem spawn: close $spawn_id
Alternativy Různé projekty implementují funkčnost podobnou Expectu v jiných jazycích – C#, Java, Scala, Groovy, Perl, Python, Ruby, Shell a Go. Obecně se nejedná o přesné klony původního Expectu, ale často se mu velmi podobají.
C# Expect.NET – funkčnost Expectu pro C# (.NET) DotNetExpect – Expectem inspirovaná knihovna pro automatizaci konzolových programů pro .NET
Java expect4j – pokus o klon původního Expectu v jazyce Java ExpectJ – další implementace unixového programu expect v jazyce Java Expect-pro-Java – čistě javová implementace nástroje Expect expect4java – javová implementace nástroje Expect, která podporuje vnořené clousures. Existuje také wrapper pro Groovy DSL.
Scala scala-expect – implementace velmi malé podmnožiny funkčnosti nástroje Expect pro jazyk Scala.
Groovy expect4groovy – implementace nástroje Expect pro Groovy DSL.
Perl Expect.pm – Perlový modul
Python Pexpect – modul pro Python pro řízení interaktivních programů v pseudoterminálu winpexpect – port pexpect na platformu Windows
Ruby RExpect – přímá náhrada modulu expect.rb ze standardní knihovny. Expect4r – Komunikace s Cisco IOS, IOS-XR a Juniper JUNOS CLI
Shell Empty – program podobný Expectu pro spouštění interaktivních příkazů v unixových shellových skriptech
Go GoExpect – balíček podobný Expectu pro jazyk Go
Odkazy
Reference
Literatura
"Advanced Programming in Expect: A Bulletproof Interface"
Externí odkazy
Oficiální website Expect na SourceForge Expect stránka – na Wiki pro uživatele Tcl IBM Blog
Kategorie:Skriptovací jazyky Kategorie:Svobodný software