Expect

Expect
VývojářNils Carlson
Aktuální verze5.45.1 (2012-08-15)
Operační systémPOSIX, Windows
Vyvíjeno vTcl
Typ softwarusvobodný software, command line interface language, programovací jazyk a autoclick
LicenceSvobodný software[1]
Webexpect.sourceforge.net
Některá data mohou pocházet z datové položky.

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

Scala

Groovy

Perl

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

Odkazy

Reference

V tomto článku byl použit překlad textu z článku Expect na anglické Wikipedii.

  1. Expect FAQ: Our company policy requires a license to use Expect. Where can we get a license? [online]. Dostupné online. 

Literatura

Externí odkazy