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:"  

  # 输入用户名，并等待服务器询问密码
  send "$my_user_id\r"
  expect "password:"  

  # 输入密码，并等待键入需要运行的命令
  send "$my_password\r"
  expect "%"  

  # 输入预先定好的密码，等待运行结果
  send "$my_command\r"
  expect "%"  

  # 将运行结果存入到变量中，显示出来或者写到磁盘中
  set results $expect_out(buffer)  

  # 退出telnet会话，等待服务器的退出提示EOF
  send "exit\r"
  expect eof
```

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

```
  # 向远程服务器请求打开一个FTP会话，并等待服务器询问用户名
  spawn ftp $remote_server
  expect "username:"  

  # 输入用户名，并等待服务器询问密码
  send "$my_user_id\r"
  expect "password:"  

  # 输入密码，并等待FTP提示符的出现
  send "$my_password\r"
  expect "ftp>"  

  # 切换到二进制模式，并等待FTP提示符的出现
  send "bin\r"
  expect "ftp>"  

  # 关闭ftp的提示符
  send "prompt\r"
  expect "ftp>"  

  # 下载所有文件
  send "mget *\r"
  expect "ftp>"  

  # 退出此次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（頁面存檔備份，存於網際網路檔案館）