Expect

Expect是Unix系統中用來進行自動化控制和測試的軟體工具，由Don Libes製作，作為Tcl腳本語言的一個擴展，應用在交互式軟體中如telnet，ftp，Passwd，fsck，rlogin，tip，ssh等等。該工具利用Unix偽終端包裝其子進程，允許任意程序通過終端接入進行自動化控制；也可利用Tk工具，將交互程序包裝在X11的圖形使用者界面中。

## 基本介紹

Expect含有利用正則表達式進行模式匹配以及通用的編程功能，允許簡單的腳本智能地管理如下工具：telnet,ftp和ssh（這些工具都缺少編程的功能），宏以及其它程序。Expect腳本的出現使得這些老的軟體工具有了新的功能和更多的靈活性。

## 例子

一個簡單的腳本程序例子就能實現自動的telnet會話：

```
  # 假定 $remote_server, $my_user_id, $my_password, 和$my_command 已经读入。
  # 向远程服务器请求打开一个telnet会话，并等待服务器询问用户名
  spawn telnet $remote_server
  expect "username:"<br />
  # 输入用户名，并等待服务器询问密码
  send "$my_user_id\r"
  expect "password:"<br />
  # 输入密码，并等待键入需要运行的命令
  send "$my_password\r"
  expect "%"<br />
  # 输入预先定好的密码，等待运行结果
  send "$my_command\r"
  expect "%"<br />
  # 将运行结果存入到变量中，显示出来或者写到磁盘中
  set results $expect_out(buffer)<br />
  # 退出telnet会话，等待服务器的退出提示EOF
  send "exit\r"
  expect eof
```

另一個腳本程序例子，自動建立FTP會話

```
  # 向远程服务器请求打开一个FTP会话，并等待服务器询问用户名
  spawn ftp $remote_server
  expect "username:"<br />
  # 输入用户名，并等待服务器询问密码
  send "$my_user_id\r"
  expect "password:"<br />
  # 输入密码，并等待FTP提示符的出现
  send "$my_password\r"
  expect "ftp>"<br />
  # 切换到二进制模式，并等待FTP提示符的出现
  send "bin\r"
  expect "ftp>"<br />
  # 关闭ftp的提示符
  send "prompt\r"
  expect "ftp>"<br />
  # 下载所有文件
  send "mget *\r"
  expect "ftp>"<br />
  # 退出此次ftp会话，并等待服务器的退出提示EOF
  send "bye\r"
  expect eof
```

## 用法說明

Expect是一種將現有的實用程序組合起來的膠合劑，通常考慮的是如何使Expect利用系統現有的工具解決問題而不是如何在Expect中解決問題。

Expect主要應用涉及商用軟體產品。很多這類的產品都會提供某種命令行工具，但這些工具缺乏腳本編程的能力，只是為了幫助使用者管理產品，而商家通常不會在如何實現一個穩定性好的腳本語言上耗費很多精力。Expect腳本中可以包含shell，查詢環境變量，通過執行某些Unix命令獲得更多的資訊，然後在產品所帶命令行接口中加入必須的資訊，來完成使用者的目標。在產品命令行接口中查詢相關資訊，該腳本可以在多種選擇中智能地決定當前應該做什麼比較合適。

每次Expect操作完成，運行結果將保存在本地環境變量 $expect_out 中。這允許腳本收集這些資訊給使用者以相應的反饋，同時也允許根據當前情況發送相對應的指令。

Expect通常用來建立一組測試套件，可以用在程序、組件或者嵌入式系統中。DejaGnu就是利用Expect寫成的一組測試套件。它被大量地應用於測試 gcc，對於遠程目標的測試例如嵌入式開發也是非常合適的。

你可以利用一種叫作"autoexpect"的工具，自動生成expect腳本。這個工具觀測你的操作，並利用啟發性知識生成expect腳本。儘管生成的代碼可能會很長，含義上有點模糊，你可以修改生成的腳本使它成為你需要的代碼。

## 觀點

### 利

Expect可通過cron封裝系統管理任務，在規定的時期運行。能夠這樣做是因為Expect僅僅使用已經安裝在主機中的系統管理工具，不需要學習額外的工具。如果程式設計師學過Tcl，那麼轉移到Expect是一件非常簡單的工作，相同的編程結構和語法，再加上一些內置的額外功能。

業界對室內管理任務使用Expect提供了很大的支持。Expect在很多的公司廣泛使用，例如Silicon Graphics, IBM, HP, Sun, Xerox, Amdahl, Tektronix, AT&T, ComputerVision和世界銀行，利用Expect對開發項目、文件傳輸、帳號管理、網路測試進行室內自動測試。

Expect已經以多種模塊的方式移植到Python和Perl語言中。Expect命令的部分子集移植到Java和嵌入到SwichTermJ（基於Java的終端仿真器）之中。這些例行程序通常是原程序的同等功能的另一種解釋方式。一旦你理解了其中的概念，如果需要的話，換到其它語言，也就很容易了。

### 弊

Expect繼承了Tcl的語法規範，對於使用其它腳本語言的人來說這是相當陌生的。和其它語言如bash、csh和Perl相比，Expect的語法模式是不同的。就像有時候一個變量的前綴冠以"$"，有時候又不需要。有些版本的Expect和Perl、Python語言的語法倒是很相似的。

另一個缺陷是在不同的平台移植Expect腳本很難。例如，一個Expect腳本使用基於Unix的工具，就不可能適合移植到Windows平台。如果可能的話，程式設計師必須找到相應的命令行程序，能夠提供相同的資訊，這就可能需要修改expect腳本的send部分，而這部分恰恰就是整個腳本的核心。如果你使用的是tcl,perl或者python這些獨立於平台的工具，使用它們各自的POSIX接口訪問文件、對遠端交互進行標準的POSIX處理（telnet,ftp等等），就不會出現上述問題。

一個不明顯的缺陷是，有時Expect可能並不是解決問題的最好方法。例如，一個系統管理員需要登錄到多個伺服器，這些自動的操作要使用Expect就得配以保存的密碼，而不是更安全的解決方案採用ssh代理密鑰。雖然這種自動交互工具很吸引人，但是還是有很多其它的辦法可以更安全穩定地解決同樣的問題。

Expect自動化控制命令行工具，但是對圖形使用者界面就失效了。Windows提供了不少有價值的工具，很多是基於圖形使用者界面的，這就是Expect失效的地方了。Windows下圖形界面程序可以通過像Autohotkey或者AutoIt等工具來實現自動化控制。

## 外部引用

- Expect on SourceForge (current)
- Official homepage (very outdated!)
- The Tcler's Wiki -- Expect page
- Perl Expect.pm module
- Pexpect a Pure Python Expect-like module
- Expect Scripting Tutorial
- Empty - expectlike tool to run command-line interactive programs in UNIX shell-scripts
- Expect-lite -- a wrapper for expect, making automation easy, quick, and fun
- Bulletproof: Reliable CLI interface using Expect
- ExpectJ - a Java implementation of the Unix expect utility

## 基本資料

- 作者：Don Libes
- 程式語言：C
- 作業系統：POSIX, Windows
- 許可協議：公有領域