Linux / Unix命令期望

預計是根據腳本與其他交互式程序進行交流的程序。 在腳本之後,Expect知道程序可以預期什麼,以及正確的響應應該是什麼。 解釋型語言提供分支和高級控制結構來指導對話。 另外,用戶可以在需要時直接控制和交互,然後將控制權返回給腳本。

Expectk是Expect和Tk的混合體。 它的行為就像Expect和Tk的願望。 沒有Tcl,Expect也可以直接在C或C ++中使用。

“Expect”這個名字來自uucp,kermit和其他調製解調器控製程序所普及的send / expect序列的思想。 然而,與uucp不同,Expect是泛化的,因此它可以作為任何程序和任務的用戶級命令運行。 期望可以同時與幾個程序交談。

什麼期望可以做

例如,以下是expect命令可以執行的一些操作:

有多種原因導致shell無法執行這些任務。 所有可能與預期。

通常,Expect對於運行需要程序和用戶之間交互的任何程序很有用。 所有這一切都是必要的,可以通過編程來表徵交互。 期望也可以在不停止正在控制的程序的情況下對用戶進行控制。 同樣,用戶可以隨時將控制權返回給腳本。

用法

Expect讀取cmdfile以獲取要執行的命令列表。 可以在支持#!的系統上隱式調用期望值。 通過將腳本標記為可執行文件並在腳本中創建第一行:

#!/ usr / local / bin / expect -f

當然,路徑必須準確地描述期望生活的地方。 / usr / local / bin只是一個例子。

-c標誌表示要在腳本中的任何腳本之前執行的命令。 應引用該命令以防止被shell破壞。 該選項可能會多次使用。 多個命令可以用一個-c通過用分號分隔來執行。 命令按它們出現的順序執行。 使用Expectk時,此選項被指定為-command。

-d標誌啟用一些診斷輸出,主要報告諸如期望和交互等命令的內部活動。 此標誌與Expect腳本開頭處的“exp_internal 1”具有相同的效果,並且還會打印Expect版本。

-D標誌啟用交互式調試器。 應該有一個整數值。 如果該值不為零,或者如果按下^ C或命中斷點,或者其他適當的調試器命令出現在腳本中,則調試器將在下一個Tcl過程之前進行控制。 使用Expectk時,該選項被指定為- Debug。

-f標誌表示一個文件,從中讀取命令。 標誌本身是可選的,因為它僅在使用#時才有用! 符號,以便可以在命令行上提供其他參數。 當使用Expectk時,這個選項被指定為-file。

默認情況下,命令文件被讀入內存並執行完整。 偶爾需要一次讀取一行文件。 為了強制以這種方式處理任意文件,請使用-b標誌。 當使用Expectk時,這個選項被指定為-buffer。

如果字符串“ - ”作為文件名提供,則讀取標準輸入。 使用“./-”從實際名為“ - ”的文件讀取。

-i標誌使Expect交互式地提示輸入命令,而不是從文件中讀取它們。 通過退出命令或EOF終止提示。 如果既不使用命令文件也不使用-c,則假定-i標誌。 使用Expectk時,此選項被指定為-interactive。

- 可以用來界定選項的結尾。 如果您希望在沒有Expect解釋的情況下將類似選項的參數傳遞給腳本,這非常有用。 這可以有用地放在#! 以防止預期的任何旗幟式解釋。 例如,以下內容會將原始參數(包括腳本名稱)保留在變量argv中

#!/ usr / local / bin / expect -

請注意,向#!添加參數時必須遵守通常的getopt (3)和execve(2)約定。 線。

如果存在文件$ exp_library / expect.rc,則會自動採購,除非使用-N標誌。 (使用Expectk時,這個選項被指定為-NORC。)在此之後,除非使用了-n標誌,否則文件〜/ .expect.rc會自動採集。 如果定義了環境變量DOTDIR,則將其視為目錄,並從中讀取.expect.rc。 使用Expectk時,此選項指定為-norc。 只有在執行任何-c標誌後才會發生此採購。

-v導致期望打印其版本號並退出。 Expectk中使用長標誌名稱的相應標誌是-version。

可選參數被構造成一個列表並存儲在名為argv和。 argc被初始化為argv的長度。

如果不使用腳本,Argv0被定義為腳本或二進製文件的名稱。 例如,以下輸出腳本的名稱和前三個參數:

send_user“$ argv0 [lrange $ argv 0 2] \ n”

命令

Expect使用工具命令語言。 Tcl提供了控制流(如果需要中斷),表達式評估以及其他一些特性,如遞歸和過程定義。 這裡使用但未定義的命令(set,if,exec)是Tcl命令。 Expect支持其他命令。 除非另外指定,否則命令將返回空字符串。

命令按字母順序列出,以便它們可以快速定位。 但是,新用戶可能會發現通過閱讀spawn,發送,期望和交互的順序來更容易開始。

關閉[-slave] [-onexec 0 | 1] [-i spawn_id]

關閉與當前進程的連接。 大多數交互式程序會在他們的stdin上檢測EOF並退出; 因此關閉通常足以殺死進程 。 -i標誌聲明進程關閉對應於命名的spawn_id。

期望和交互都會檢測當前進程何時退出並隱式執行結束,但如果通過例如“exec kill $ pid”來終止進程 ,則需要明確地調用close

-onexec標誌確定是否在任何新產生的進程中關閉了spawn id,或者是否覆蓋了進程 。 要使spawn id保持打開狀態,請使用值0.非零整數值將強制在任何新進程中關閉spawn。

-slave標誌關閉與spawn id關聯的從機。 當連接關閉時,如果奴隸仍然打開,奴隸也會自動關閉。

不管連接是隱式關閉還是顯式關閉,都應該調用wait來清除相應的內核進程槽。 close命令不會調用wait,因為不能保證關閉進程連接會導致它退出。

調試[[--now] 0 | 1]

控制一個Tcl調試器,允許您逐句執行語句並設置斷點。

沒有參數時,如果調試器沒有運行,則返回1,否則返回0。

有了1個參數,調試器就會啟動。 使用0參數時,調試器停止。 如果1參數前面有-now標誌,則立即啟動調試器。 否則,調試器將以下一個Tcl語句啟動。

調試命令不會更改任何陷阱。 使用-D標誌將此與啟動Expect進行比較。

disconnect命令斷開終端的分叉進程 。 它繼續在後台運行。 該過程有其自己的過程組。 標準I / O被重定向到/ dev / null

以下片段使用斷開連接來繼續在後台運行腳本。

如果{[fork]!= 0}退出斷開連接。 。 。

以下腳本讀取密碼,然後每小時運行一個程序,每次運行時都要求輸入密碼。 腳本提供密碼,以便您只需輸入一次即可。

send_user“password?\”expect_user -re“(。*)\ n”{} 1 {} {if {[fork]!= 0} {sleep 3600; continue} disconnect spawn priv_prog expect Password:send“$ expect_out 1,字符串)\ r“。 。 。 出口 }

在外殼異步過程特徵(&)上使用斷開連接的優點是,Expect可以在斷開連接之前保存終端參數,然後將它們應用於新的ptys。 使用&時,Expect沒有機會讀取終端的參數,因為終端在Expect接收控制時已斷開連接。

退出[-opts] [狀態]

導致期望退出或準備這樣做。

-onexit標誌導致下一個參數被用作退出處理程序。 沒有參數,返回當前的退出處理程序。

-noexit標誌導致Expect準備退出,但是沒有實際將控制權返回給操作系統。 用戶定義的退出處理程序與Expect自己的內部處理程序一樣運行。 不應再執行其他期望的命令。 如果您使用其他Tcl擴展運行Expect,這很有用。 當前的解釋器(和主窗口,如果在Tk環境中)仍然保持其他Tcl擴展可以清理。 如果Expect的退出再次被調用(但是可能發生這種情況),則處理程序不會重新運行。

退出後,所有關於產生的進程的連接都將關閉。 生成的進程會將封閉檢測為EOF。 退出除了正常的_exit(2)過程所做的操作之外不會採取其他操作。 因此,不會檢查EOF的衍生進程可能會繼續運行。 (例如,各種條件對於確定產生的進程將發送什麼信號很重要,但這些是依賴於系統的,通常在退出(3)中進行記錄。)繼續運行的衍生進程將由init繼承。

狀態 (如果未指定,則為0)作為Expect的退出狀態返回。 如果到達腳本的末尾,則退出將隱式執行。

exp_continue [-continue_timer]
命令exp_continue允許期望自己繼續執行而不是像往常那樣返回。 默認情況下, exp_continue重置超時定時器。 -continue_timer標誌防止重啟計時器。 (請看更多信息。)

exp_internal [-f文件]值
如果不為零,則會導致進一步的命令將內部診斷信息發送到期望值 stderr 。 如果值為 0,則此輸出被禁用。診斷信息包括接收到的每個字符,並且每次嘗試都將當前輸出與模式匹配。

如果提供了可選文件 ,則將所有正常和調試輸出寫入該文件(不管值的 )。 以前的任何診斷輸出文件都已關閉。

-info標誌使exp_internal返回給定的最近的非信息參數的描述。

exp_open [args] [-i spawn_id]
返回一個對應於原始spawn id的Tcl文件標識符。 文件標識符可以像使用Tcl的打開命令打開一樣使用 。 (spawn id不應該再使用,不應該執行等待

-leaveopen標誌通過Expect命令將spawn id打開以供訪問。 必須在spawn id上執行等待

exp_pid [-i spawn_id]
返回當前派生進程對應的進程ID。 如果使用-i標誌,則返回的pid對應於給定spawn id的pid

exp_send
發送的別名。

exp_send_error
send_error的別名。

exp_send_log
send_log的別名。

exp_send_tty
send_tty的別名。

exp_send_user
send_user的別名。

exp_version [[-exit]版本]
對於確保腳本與當前版本的Expect兼容很有用。

沒有參數,返回當前版本的Expect 。 這個版本可能會被編碼到您的腳本中。 如果您確實知道您未使用最新版本的功能,則可以指定較早的版本。

版本由三個由點分隔的數字組成。 首先是主要數字。 為不同版本的Expect編寫的腳本幾乎肯定不起作用。 如果主要數字不匹配,則exp_version將返回錯誤。

其次是次要號碼。 編寫比當前版本號碼更小的版本的腳本可能取決於某些新功能,可能無法運行。 如果主要編號匹配,則exp_version將返回錯誤,但腳本次要編號大於正在運行的Expect的編號

第三是在版本比較中沒有參與的數字。 但是,當Expect軟件分發以任何方式進行更改(例如通過附加文檔或優化)時,它會增加。 在每個新的次要版本中,它重置為0。

使用-exit標誌, Expect會打印一個錯誤並在版本過期時退出。

期望[[-opts] pat1 body1] ... [-opts] patn [bodyn]
等待其中一個模式與衍生進程的輸出相匹配,指定的時間段已過,或者看到文件結束。 如果最後的主體是空的,它可能被省略。

最新的expect_before命令中的模式在任何其他模式之前隱式使用。 來自最近的expect_after命令的模式在任何其他模式之後隱式使用。

如果整個expect語句的參數需要多行,則所有參數都可以“加強”為一個,以避免每行都以反斜杠結尾。 在這種情況下,儘管有大括號,通常的Tcl替換仍會發生。

如果模式是關鍵字eof ,則在文件結束時執行相應的主體。 如果模式是關鍵字超時 ,則在超時時執行相應的主體。 如果沒有使用超時關鍵字,則會在超時後執行隱式空操作。 默認的超時時間是10秒,但可以通過命令“set timeout 30”將其設置為30,例如30。 無限超時可以由值-1指定。 如果模式是關鍵字default ,則在超時或文件結束時執行相應的主體。

如果模式匹配,則執行相應的主體。 expect返回body的結果(如果沒有模式匹配,則返回空字符串)。 在多個模式匹配的情況下,首先出現的模式用於選擇主體。

每次新輸出到達時,都會按照它們列出的順序與每個模式進行比較。 因此,您可以通過確保最後一個模式出現,如提示來測試是否存在匹配。 在沒有提示的情況下,您必須使用超時 (就像您手動進行交互一樣)。

模式有三種規定。 默認情況下,模式與Tcl的字符串匹配命令一樣被指定。 (這些模式也類似於通常稱為“glob”模式的C-shell正則表達式)。 -gl標誌可以用於保護可能與期望標誌匹配的模式。 任何以“ - ”開頭的模式都應該這樣保護。 (所有以“ - ”開頭的字符串都保留給將來的選項。)

例如,以下片段查找成功的登錄名。 (請注意, abort被假定為腳本中其他地方定義的一個程序。)

expect {busy {puts busy \ n; exp_continue}失敗中止“無效密碼”中止超時中止連接}

引號對於第四種模式是必要的,因為它包含一個空格,否則會將模式與動作分開。 具有相同動作的模式(例如第3和第4)需要再次列出動作。 這可以通過使用正則表達式樣式來避免(見下文)。 有關形成全局模式的更多信息可以在Tcl手冊中找到。

正則表達式樣式遵循Tcl的正則表達式 (簡稱“正則表達式”)命令定義的語法。 正則表達式模式與標誌-re一起引入。 前面的例子可以用regexp重寫為:

expect {busy {puts busy \ n; exp_continue} -re“失敗|無效密碼”中止超時中止連接}

這兩種模式都是“未固定的”。 這意味著模式不必匹配整個字符串,但可以在字符串中的任何位置開始和結束匹配(只要其他所有匹配項匹配)。 使用^匹配字符串的開頭,使用$匹配結尾。 請注意,如果您不等待字符串結束,那麼您的響應可能會很容易在字符串中間結束,因為它們是從衍生進程中回顯的。 在產生正確結果的同時,輸出看起來不自然。 因此,如果您可以準確地描述字符串末尾的字符,則鼓勵使用$。

請注意,在許多編輯器中,^和$分別與行的開頭和結尾相匹配。 但是,因為期望不是面向行的,所以這些字符匹配當前在期望匹配緩衝區中的數據的開始和結束(而不是行)。 (另請參閱下面有關“系統消化不良”的註釋。)

-ex標誌使模式匹配為“精確”字符串。 沒有對*,^等的解釋(儘管通常的Tcl約定仍然必須遵守)。 確切的模式總是未固定的。

-nocase標誌會導致輸出的大寫字符比較,就好像它們是小寫字符一樣。 該模式不受影響。

在讀取輸出時,超過2000 個字節可能會迫使較早的字節“被遺忘”。 這可以通過函數match_max來改變。 (請注意,過大的值可能會減慢模式匹配。)如果patlistfull_buffer ,則在接收到match_max字節並且沒有其他模式匹配的情況下執行相應的主體。 不管是否使用full_buffer關鍵字,忘記的字符都會寫入expect_out(buffer)。

如果patlist是關鍵字null ,並且允許NULL(通過remove_nulls命令),則在單個ASCII 0匹配時執行相應的主體。 通過glob或regexp模式不可能匹配0個字節。

在匹配一個模式(或者eof或者full_buffer)之後,任何匹配和以前不匹配的輸出將被保存在變量expect_out(buffer)中 。 通過expect_out(9,string)將多達9個正則表達式子字符串匹配保存在變量expect_out(1 ,字符串)中 。 如果在模式之前使用-indices標誌,則10個字符串的開始和結束索引(以適合於lrange的形式)存儲在變量expect_out(X,start)expect_out(X,end)中 ,其中X是數字,對應於緩衝區中的子串位置。 0指的是匹配整個模式的字符串,並為glob模式和正則表達式模式生成。 例如,如果某個進程已生成“abcdefgh \ n”的輸出,則結果為:

期待“cd”

就好像下面的語句已經執行一樣:

set expect_out(0,string)cd set expect_out(buffer)abcd

並且“efgh \ n”保留在輸出緩衝區中。 如果一個過程產生了輸出“abbbcabkkkka \ n”,結果如下:

expect -indices -re“b(b *)。*(k +)”

就好像下面的語句已經執行一樣:

set expect_out(0,start)1 set expect_out(0,end)10 set expect_out(0,string)bbbcabkkkk set expect_out(1,start)2 set expect_out(1,end)3 set expect_out(1,string)bb set expect_out (2,start)10 set expect_out(2,end)10 set expect_out(2,string)k set expect_out(buffer)abbbcabkkkk

並且“a \ n”保留在輸出緩衝區中。 模式“*”(和-re“。*”)將刷新輸出緩衝區而不讀取進程的任何更多輸出。

通常,匹配的輸出將從Expect的內部緩衝區中丟棄。 這可以通過在-notransfer標誌前加一個模式來防止。 這個標誌在實驗中特別有用(為了方便,在試驗時可以縮寫為“-not”)。

與匹配輸出(或eof或full_buffer)關聯的spawn id存儲在expect_out(spawn_id)中

-timeout標誌導致當前的expect命令將下面的值用作超時而不是使用超時變量的值。

默認情況下,模式與當前進程的輸出匹配,但-i標誌聲明命名spawn_id列表的輸出與任何後續模式匹配(直到下一個-i )。 spawn_id列表應該是Spawn_ids的空白分隔列表或引用這樣的spawn_ids列表的變量。

例如,以下示例等待來自當前進程的“連接”,或等待$ proc2命名的spawn_id中的“busy”,“failed”或“invalid password”。

預計{-i $ proc2 busy {puts busy \ n; exp_continue} -re“失敗|無效密碼”中止超時中止連接}

全局變量any_spawn_id的值可用於將模式與當前expect命令中所有其他-i標誌命名的spawn_id進行匹配。 來自沒有關聯模式的-i標誌的spawn_id(即緊接著另一個-i )可用於與any_spawn_id相關的相同expect命令中的任何其他模式

-i標誌也可以命名全局變量,在這種情況下,讀取變量以獲得spawn id列表。 只要變化發生,變量就會被重讀。 這提供了一種在命令執行時更改I / O源的方法。 提供這種方式的產卵ids被稱為“間接”產卵ids。

諸如breakcontinue之類的操作會導致控制結構(即forproc )以通常的方式運行。 命令exp_continue允許期望自己繼續執行而不是像往常那樣返回。

這對避免顯式循環或重複期望語句很有用。 以下示例是rlogin自動化片段的一部分。 exp_continue避免瞭如果rlogin提示輸入密碼,則必須編寫第二個expect語句(再次查找提示)。

在$ host:“expect_user -re”(。*)\ n“send_user”\ n“send”$ expect_out(1,字符串)\ r“stty中預期{密碼:{stty -echo send_user” echo exp_continue}不正確{send_user“無效密碼或帳戶\ n”退出}超時{send_user“連接到$主機超時\ n”退出} eof {send_user \“連接到主機失敗:$ expect_out(buffer)”exit} - 重新$提示}

例如,以下片段可能有助於用戶指導已經完全自動化的交互。 在這種情況下,終端進入原始模式。 如果用戶按下“+”,則會增加一個變量。 如果按下“p”,則會向該進程發送多個返回值,可能以某種方式戳它,而“i”則讓用戶與進程交互,從而有效地從腳本中竊取控制權。 在每種情況下, exp_continue都允許當前期望在執行當前操作後繼續進行模式匹配。

stty raw -echo expect_after {-i $ user_spawn_id“p”{send“\ r \ r \ r”; exp_continue}“+”{incr foo; exp_continue}“i”{interact; exp_continue}“quit”exit}

默認情況下, exp_continue重置超時定時器。 如果使用-continue_timer標誌調用exp_continue ,定時器不會重新啟動。

expect_after [expect_args]
expect_before的工作方式相同,只是如果來自expectexpect_after的模式可以匹配,則使用預期模式。 有關更多信息,請參閱expect_before命令。

expect_background [expect_args]
採用與期望相同的參數,但是它立即返回。 每當新輸入到達時都會測試模式。 模式超時默認expect_background沒有意義,並且被默默丟棄。 否則, expect_background命令就像expect一樣使用expect_beforeexpect_after模式。

expect_background操作正在評估時,同一spawn id的後台處理被阻止。 後台處理在操作完成時解鎖。 當後台處理被阻止時,可以對相同的spawn id進行(前台) 期望

expect_background未被阻止的情況下執行預期不可能的。 通過使用相同的spawn id聲明新的expect_background來刪除特定spawn id的expect_background。 在沒有模式的情況下聲明expect_background會將匹配的spawn id從匹配背景中的模式的能力中移除。

expect_before [expect_args]
採用與期望相同的參數,但是它立即返回。 具有相同spawn id的最近expect_before中的模式動作對隱式添加到以下任何expect命令中。 如果一個模式匹配,它將被視為在expect命令本身中指定的,並且關聯主體在expect命令的上下文中執行。 如果來自expect_beforeexpect的模式可以匹配,則使用expect_before模式。

如果未指定模式,則不檢查派生標識以查找任何模式。

除非由-i標誌覆蓋,否則expect_before模式與在執行expect_before命令時定義的spawn id相匹配(而不是在其模式匹配時)。

-info標誌會導致expect_before返回它將匹配的模式的當前規範。 默認情況下,它會報告當前的spawn id。 可以給出一個可選的spawn id規範來獲取該spawn id的信息。 例如

expect_before -info -i $ proc

最多可以給出一個spawn id規範。 標誌-indirect抑制直接來自間接規範的spawn id。

而不是spawn id規範,標誌“-all”將導致“-info”報告所有生成ids。

-info標誌的輸出可以重新用作expect_before的參數。

expect_tty [expect_args]
就像期待的一樣,但它讀取/ dev / tty中的字符(即用戶的擊鍵)。 默認情況下,閱讀是在烹飪模式下進行的。 因此,線路必須以回報結束,以期望看到它們。 這可以通過stty改變(參見下面的stty命令)。

expect_user [expect_args]
就像期望的一樣,但是它從標準輸入讀取字符(即用戶的擊鍵)。 默認情況下,閱讀是在烹飪模式下進行的。 因此,線路必須以回報結束,以期望看到它們。 這可以通過stty改變(參見下面的stty命令)。

叉子
創建一個新的過程 。 新進程是當前Expect 進程的精確副本。 成功時, fork將返回0給新(子) 進程 ,並將子進程進程 ID返回給父進程 。 在失敗時(總是由於缺乏資源,例如交換空間,內存), fork向父進程返回-1,並且沒有創建子進程

通過退出命令退出分叉進程,就像原始進程一樣 。 分叉的進程被允許寫入日誌文件。 如果您不禁用大多數進程的調試或日誌記錄,結果可能會造成混淆。

一些pty實現可能會被多個讀者和作者混淆,即使是暫時的。 因此,在產卵過程之前分叉是最安全的。

交互[string1 body1] ... [stringn [bodyn]]
將當前進程的控制權交給用戶,以便將鍵擊發送到當前進程 ,並返回當前進程的stdout和stderr。

字符串主體對可以被指定為參數,在這種情況下,當輸入相應的字符串時執行主體。 (默認情況下,字符串不會發送到當前進程 。)假定解釋器命令(如果最後一個主體缺失)。

如果整個交互語句的參數需要多行,則所有參數都可以“加強”為一行,以避免每行都以反斜杠結尾。 在這種情況下,儘管有大括號,通常的Tcl替換仍會發生。

例如,以下命令運行時會與定義的以下字符串 - 主體對進行交互:按^ Z時, Expect被掛起。 ( -reset標誌恢復終端模式。)當^ A被按下時,用戶看到“你輸入了一個控制-A”並且該過程被發送^ A。 當按下$時,用戶看到日期。 按^ C時, Expect退出。 如果輸入“foo”,用戶將看到“bar”。 當按下~~時, Expect解釋器以交互方式運行。

設置CTRLZ \ 032 interact {-reset $ CTRLZ {exec kill -STOP [pid]} \ 001 {send_user“你鍵入了一個控制-A \ n”; 發送“\ 001”} $ {send_user“日期是[clock format [clock seconds]]。”} \ 003 exit foo {send_user“bar”} ~~}

在字符串正文對中,字符串按照它們作為參數列出的順序進行匹配。 部分匹配的字符串不會被發送到當前進程,以預期剩餘字符串。 如果字符被輸入以致不再有可能匹配,則只有字符串的一部分將被發送到不可能開始另一匹配的進程 。 因此,如果嘗試匹配的原始字符串最終失敗,那麼作為部分匹配子字符串的字符串可以稍後匹配。

默認情況下,字符串匹配確切無法使用通配符 。 (相比之下, expect命令默認使用全局樣式模式。)- ex標誌可用於保護可能與交互標誌匹配的模式。 任何以“ - ”開頭的模式都應該這樣保護。 (所有以“ - ”開頭的字符串都保留給將來的選項。)

-re標誌強製字符串被解釋為正則表達式樣式。 在這種情況下,匹配的子字符串存儲在變量interact_out中,類似於expect將其輸出存儲在變量expect_out中的方式-indices標誌同樣受支持。

模式eof引入了一個在文件結束時執行的動作。 一個單獨的eof模式也可能跟在-output標誌後面,在這種情況下,如果在寫入輸出時檢測到eof,它將與之匹配。 默認的eof動作是“return”,因此交互只是返回任何EOF。

模式超時引入超時(以秒為單位)以及在給定時間內未讀取任何字符後執行的操作。 超時模式適用於最近指定的進程 。 沒有默認超時。 特殊變量“timeout”(由expect命令使用)對此超時沒有影響。

例如,以下語句可用於自動登出一小時內沒有鍵入任何內容但仍有頻繁系統消息的用戶:

交互-input $ user_spawn_id超時3600返回-output \ $ spawn_id

如果模式是關鍵字null ,並且允許空值(通過remove_nulls命令),則在單個ASCII 0匹配時執行相應的主體。 通過glob或regexp模式不可能匹配0個字節。

使用-iwrite標誌預填模式會導致變量interact_out(spawn_id)被設置為與模式(或eof)匹配的spawn_id。

諸如breakcontinue之類的操作會導致控制結構(即forproc )以通常的方式運行。 然而返回原因交互返回到它的調用者,而inter_return導致交互導致其調用者返回。 例如,如果“proc foo”調用交互 ,然後執行inter_return動作, proc foo將返回。 (這意味著如果交互式交互調用解釋器 ,則返回將導致交互繼續,而inter_return將導致交互返回到其調用者。)

交互過程中 ,使用原始模式,以便所有字符都可以傳遞給當前進程 。 如果當前進程沒有捕獲到作業控制信號,則在發送停止信號時(默認為^ Z),它將停止。 要重新啟動它,請發送一個繼續信號(例如通過“kill -CONT”)。 如果你真的想發送一個SIGSTOP到這樣的進程 (^ Z),考慮先產生csh,然後運行你的程序。 另一方面,如果你想發送一個SIGSTOP到Expect本身,首先調用解釋器(也許使用一個轉義字符),然後按^ Z。

字符串主體對可以用作避免必須以交互方式進入解釋器和執行命令的簡寫。 前一個終端模式在執行字符串主體對的主體時使用。

為了提高速度,默認情況下,操作以原始模式執行 -reset標誌將終端重置為它執行交互之前的模式(總是為熟化模式)。 請注意,切換模式時輸入的字符可能會丟失(某些系統中終端驅動程序的不幸功能)。 使用-reset的唯一原因是如果您的操作取決於在熟化模式下運行。

-echo標誌將與以下模式相匹配的字符發回到在讀取每個字符時生成它們的進程 。 當用戶需要查看部分類型模式的反饋時,這可能會很有用。

如果一個模式被回顯,但最終無法匹配,這些字符將被發送到派生進程 。 如果產生的過程回應它們,用戶將看到兩個字符。 -echo可能僅適用於用戶不太可能無法完成該模式的情況。 例如,以下摘錄來自rftp,即recursive-ftp腳本,其中提示用戶輸入〜g,〜p或〜l以遞歸地獲取,放入或列出當前目錄。 這些遠離正常的ftp命令,用戶不太可能輸入〜其次,除了錯誤之外,在這種情況下,他們可能會忽略結果。

交互{-echo〜g {getcurdirectory 1} -echo〜l {getcurdirectory 0} -echo〜p {putcurdirectory}}

當字符被讀取時, -nobuffer標誌將與以下模式匹配的字符發送到輸出進程

當你想讓程序回顯模式時,這很有用。 例如,以下內容可能用於監視某人正在撥打的位置(海耶斯式調製解調器)。 每次看到“atd”腳本都會記錄該行的其餘部分。

proc lognumber {} {interact -nobuffer -re“(。*)\ r”return puts $ log“[clock format [clock seconds]]:dialed $ interact_out(1,string)”} interact -nobuffer“atd”lognumber

交互期間,以前使用log_user將被忽略。 特別是, 交互會迫使其輸出被記錄(發送到標準輸出),因為它被假定為用戶不希望盲目交互。

-o標誌將導致任何後續的鍵身對應用於當前進程的輸出。 例如,在處理在Telnet會話期間發送不需要的字符的主機時,這可能很有用。

默認情況下, 交互期望用戶寫入stdin並讀取Expect 進程本身的stdout。 -u標誌(用於“用戶”)使得交互將用戶看作由其參數命名的進程 (其必須是衍生的id)。

這允許兩個不相關的進程在不使用顯式循環的情況下連接在一起。 為了幫助調試,Expect的診斷程序總是轉到stderr(或者stdout用於某些日誌記錄和調試信息)。 出於同樣的原因, 解釋器命令將從stdin交互式讀取。

例如,下面的片段創建一個登錄過程 。 然後撥打用戶(未顯示),最後連接兩者。 當然,任何進程都可以替代登錄。 例如,一個外殼將允許用戶在不提供帳戶和密碼的情況下工作。

產卵登錄設置登錄$ spawn_id spawn提示調製解調器#撥回給用戶#連接用戶登錄相互作用-u $登錄

要將輸出發送到多個進程,請列出以-output標誌開頭的每個spawn id列表。 一輸出spawn id的輸入可以由一個以-input標誌開頭的spawn id列表確定。 (除了any_spawn_id在交互中沒有意義外,-input和-output都可以採用與expect命令中的-i標誌形式相同的列表。)以下所有標誌和字符串 (或模式)均適用於該輸入,直到另一個 -輸入標誌出現。 如果沒有輸入, 輸出意味著“-input $ user_spawn_id -output”。 (同樣,對於沒有輸入的模式)。如果指定了一個輸​​入,它將覆蓋$ user_spawn_id。 如果指定了第二個輸入,它將覆蓋$ spawn_id。 可以指定附加的輸入標誌。

兩個隱含的輸入過程默認將其輸出指定為$ spawn_id和$ user_spawn_id(反向)。 如果出現的輸入標誌沒有輸出標誌,則該進程的字符將被丟棄。

當沒有使用其他輸入或輸出標誌時, -i標誌引入了對當前spawn_id的替換。 -i標誌意味著-o標誌。

通過使用間接spawn id可以更改正在與之交互的進程。 (關於expect命令的部分介紹了間接spawn id。)可以使用-i,-u,-input或-output標誌指定間接spawn id。

口譯員[args]
使交互式提示用戶輸入Expect和Tcl命令。 每個命令的結果都被打印出來。

諸如breakcontinue之類的操作會導致控制結構(即forproc )以通常的方式運行。 然而, 返回會導致解釋器返回到調用者,而inter_return會導致解釋器在其調用者中返回。 例如,如果“proc foo”調用解釋器然後執行inter_return動作, proc foo將返回。 任何其他命令都會導致解釋器繼續提示新命令。

默認情況下,提示包含兩個整數。 第一個整數描述評估堆棧的深度(即,調用了多少次Tcl_Eval)。 第二個整數是Tcl歷史標識符。 提示可以通過定義一個名為“prompt1”的過程來設置,該過程的返回值將成為下一個提示。 如果一條語句有開引號,括號,大括號或括號,則在換行符時會發出次要提示(默認為“+>”)。 輔助提示符可以通過定義稱為“prompt2”的過程來設置。

解釋器中 ,即使調用者使用原始模式,也會使用烹飪模式。

如果stdin被關閉, 解釋器將返回,除非使用了-eof標誌,在這種情況下調用後續的參數。

log_file [args] [[-a]文件]
如果提供了文件名, log_file將在文件中記錄會話的記錄( 從那一點開始)。 如果沒有參數, log_file將停止記錄。 任何以前的日誌文件已關閉。

可以使用-open-leaveopen標誌來提供Tcl文件標識符,而不是文件名。 這與spawn命令類似。 (見更多信息產生 。)

-a標誌強制輸出記錄被log_user命令抑制。

默認情況下, log_file命令附加到舊文件而不是截斷它們,以方便在一個會話中關閉和多次關閉日誌。 要截斷文件,請使用-noappend標誌。

-info標誌使得log_file返回給定的最近的非信息參數的描述。

log_user -info | 0 | 1
默認情況下,發送/預期對話被記錄到標準輸出(如果打開,則會記錄一個日誌文件)。 通過命令“log_user 0”禁用日誌記錄到stdout,並通過“log_user 1”重新啟用日誌記錄。 記錄到日誌文件沒有改變。

-info標誌使得log_user返回給定的最近的非信息參數的描述。

match_max [-d] [-i spawn_id] [size]
定義期望內部使用的緩衝區大小(以字節為單位)。 如果沒有大小參數,則返回當前大小。

使用-d標誌設置默認大小。 (初始默認值是2000.)使用-i標誌時,大小將被設置為指定的spawn ID,否則它將被設置為當前進程

疊加[ - #spawn_id] [ - #spawn_id] [...]程序[args]
執行“程序參數”代替當前的Expect程序,該程序終止。 一個純粹的連字符參數在命令名之前強制使用連字符,就像它是一個登錄shell一樣。 除了那些以參數命名的spawn_ids之外,所有spawn_id都是關閉的 這些映射到指定的文件標識符。

Spawn_ids被映射到新程序繼承的文件標識符。 例如,下面一行運行國際象棋,並允許它由當前進程控制 - 比如國際象棋大師。

覆蓋-0 $ spawn_id -1 $ spawn_id -2 $ spawn_id國際象棋

這比“交互-u”更有效,然而,由於Expect 過程不再受控,它會犧牲進行編程交互的能力。

請注意,不提供控制終端。 因此,如果您斷開或重新映射標準輸入,執行作業控制(shell,登錄等)的程序將無法正常運行。

奇偶校驗[-d] [-i spawn_id] [值]
定義是否應從產生的進程的輸出中保留或刪除奇偶校驗。 如果為零,則會剝離奇偶校驗,否則不會剝離。 沒有參數時,返回當前值。

使用-d標誌,默認的奇偶校驗值被設置。 (初始默認值為1,即奇偶校驗未被剝離。)使用-i標誌,將為指定的spawn id設置奇偶校驗值,否則將為當前進程設置奇偶校驗值。

remove_nulls [-d] [-i spawn_id] [value]
定義在模式匹配或存儲在變量expect_outinteract_out之前,是否保留或從生成的進程的輸出中刪除了空值。 如果值為 1,則刪除空值。 如果值為 0,則不刪除空值。 沒有參數時,返回當前值。

-d標誌設置默認值。 (初始默認值為1,即空值被刪除。)使用-i標誌,將為指定的spawn id設置該值,否則將為當前進程設置該值。

無論是否刪除空值, Expect都會將空字節記錄到日誌和標準輸出中。

發送[-flags]字符串
字符串發送到當前進程 。 例如,該命令

發送“hello world \ r”

將字符helloworld發送到當前進程 。 (Tcl包含一個可以構建任意複雜字符串的類似printf的命令(稱為格式 )。)

雖然帶有行緩衝輸入的程序在發送返回字符之前不會讀取字符,但會立即發送字符。 返回字符用“\ r”表示。

-標誌強制下一個參數被解釋為一個字符串而不是一個標誌。 任何字符串都可以以“ - ”開頭,不管它是否看起來像一個標誌。 這提供了一種可靠的機制來指定變量字符串,而不會被偶然看起來像標誌的那些字符串絆倒。 (所有以“ - ”開頭的字符串都保留給將來的選項。)

-i標誌聲明將該字符串發送到指定的spawn_id。 如果spawn_id是user_spawn_id ,並且終端處於原始模式,則字符串中的換行符將被轉換為返回換行符序列,以使它們看起來好像終端處於煮熟模式。 -raw標誌禁用此翻譯。

-null標誌發送空字符(0字節)。 默認情況下,發送一個null。 一個整數可以跟在-null後面以指示要發送多少個空值。

-break標誌產生一個中斷條件。 這只有在spawn id引用通過“spawn -open”打開的tty設備時才有意義。 如果你已經產生了一個過程 ,如提示,你應該使用提示的慣例產生一個休息。

-s標誌強制輸出將被“緩慢”發送,從而避免出現這種情況,即計算機對輸入緩衝區進行了突破,這種輸入緩衝區專為永遠不會輸入相同緩衝區的人設計。 該輸出由變量“send_slow”的值來控制,該變量採用兩個元素列表。 第一個元素是一個描述原子發送字節數的整數。 第二個元素是一個實數,它描述了原子發送必須被隔開的秒數。 例如,“set send_slow {10 .001}”將強制“send -s”在發送的每10個字符之間發送1毫秒的字符串。

-h標誌強制輸出被發送(有點),就像人類實際輸入一樣。 類似人物的延遲出現在角色之間。 (該算法基於威布爾分佈,並進行修改以適應該特定應用。)該輸出由變量“send_human”的值控制,該變量採用五元素列表。 前兩個元素是以秒為單位的字符的平均到達時間間隔。 第一個默認使用。 第二個用於單詞結尾,以模擬偶爾在這種轉換中出現的細微暫停。 第三個參數是變異性的度量,其中.1變化很大,1是合理變化的,10是相當不變的。 極端是從0到無限。 最後兩個參數分別是最小和最大間隔時間。 最後使用最小值和最大值,並將最後一次“剪輯”。 如果最小值和最大值限制足夠的值,那麼最終平均值可能與給定平均值有很大差異。

作為一個例子,下面的命令模擬一個快速和一致的打字員:

設置send_human {.1 .3 1 .05 2} send -h“我餓了,我們來做午餐吧。”

而在宿醉之後以下可能更適合:

設置send_human {.4 .4 .2 .5 100}發送-h“Goodd party lash night!”

請注意,雖然可以通過在發送參數中嵌入錯誤和更正來自己設置錯誤糾正情況,但不會模擬錯誤。

用於發送空字符,發送中斷,強制慢輸出和人類輸出的標誌是相互排斥的。 只有最後指定的那個將被使用。 而且,不能使用用於發送空字符或中斷的標誌來指定字符串參數。

按照期望將第一次發送發送流程是一個好主意。 期望等待進程啟動,而發送不能。 特別是,如果第一次發送流程開始運行之前完成,您可能會忽略數據。 在交互式程序沒有提供初始提示的情況下,您可以延遲發送 ,如下所示:

#為了避免給黑客提示如何入侵,#此系統不會提示輸入外部密碼。 #等待5秒讓exec完成spawn telnet very.secure.gov sleep 5發送密碼\ r

exp_send發送的別名 如果您在Tk環境中使用Expectk或Expect的其他變體,則發送由Tk定義,用於完全不同的目的。 exp_send是為了兼容環境而提供的。 為其他Expect的其他發送命令提供了類似的別名。

send_error [-flags]字符串
就像發送 ,除了輸出發送到stderr而不是當前進程

send_log [ - ]字符串
就像發送 ,除了字符串只發送到日誌文件(請參閱log_file 。)如果沒有打開日誌文件,參數將被忽略。

send_tty [-flags]字符串
就像發送 ,除了輸出發送到/ dev / tty而不是當前進程

send_user [-flags]字符串
就像發送 ,除了輸出發送到標準輸出而不是當前進程

睡眠秒
導致腳本在給定的秒數內休眠 。 秒可能是十進制數。 在Expect休眠時處理中斷(和Tk事件,如果您使用的是Expectk)。

spawn [args]程序[args]
創建一個運行“程序參數”的新進程 。 它的stdin,stdout和stderr被連接到Expect,以便它們可以被其他Expect命令讀取和寫入。 關閉時斷開連接或者進程本身關閉任何文件標識符。

當一個進程spawn啟動時,變量spawn_id被設置為引用該進程的描述符。 spawn_id描述的過程被認為是“當前 過程 ”。 spawn_id可以被讀取或寫入,實際上提供作業控制。

user_spawn_id是包含引用用戶的描述符的全局變量。 例如,當spawn_id被設置為這個值時, expect的行為就像expect_user

.I error_spawn_id是一個包含描述符的全局變量,它指向標準錯誤。 例如,當spawn_id設置為這個值時, send的行為就像send_error

tty_spawn_id是一個包含描述符的全局變量,該描述符引用/ dev / tty。 如果/ dev / tty不存在(例如在cron,at或批處理腳本中),則tty_spawn_id未定義。 這可能會被測試為:

如果{[info vars tty_spawn_id]} {#/ dev / tty存在} else {#/ dev / tty不存在#可能在cron,批處理或腳本中}

spawn返回UNIX 進程 ID。 如果沒有進程產生,返回0。 變量spawn_out(slave,name)被設置為pty從屬設備的名稱。

默認情況下, spawn回顯命令名稱和參數。 -noecho標誌停止產生

-console標誌使控制台輸出重定向到派生進程 。 這在所有系統上都不受支持。

在內部, spawn使用一個pty,初始化方式與用戶的tty相同。 這是進一步初始化,以便所有設置都是“健全的”(根據stty(1))。 如果定義了stty_init變量,則會以stty參數的形式將其解釋為進一步的配置。 例如,“set stty_init raw”將導致進一步產生的進程的終端以原始模式啟動。 -nottycopy跳過基於用戶tty的初始化。 -nottyinit跳過了“理智”的初始化。

通常, 產卵需要很少的時間來執行。 如果您注意到產卵需要大量時間,可能會遇到被楔入的ptys。 許多測試運行在ptys上以避免與錯誤進程的糾纏。 (這些需要花費10秒的時間)。使用-d選項運行期望將顯示Expect是否遇到奇怪狀態下的許多ptys。 如果你不能殺死這些ptys所連接的進程,你唯一的辦法就是重新啟動。

如果由於exec(2)失敗(例如程序不存在)而無法成功產生程序 ,則下一個交互expect命令將返回錯誤消息,就像程序已運行一樣,並生成錯誤消息作為輸出。 這種行為是spawn實現的自然結果。 在內部產生分叉,之後產生的進程無法與原始Expect 進程通信,除非通過spawn_id進行通信。

-open標誌將導致下一個參數被解釋為Tcl文件標識符(即,通過打開返回)。然後可以使用spawn id,就好像它是一個衍生進程 。 (不應再使用文件標識符。)這使您可以將原始設備,文件和管道視為派生進程而不使用pty。 返回0表示沒有關聯的進程 。 當與產生的進程的連接關閉時,Tcl文件標識符也是如此。 -leaveopen標誌與-open相似,只是-leaveopen會導致文件標識符在spawn id關閉後保持打開狀態。

-pty標誌導致一個pty被打開,但沒有進程產生。 返回0表示沒有關聯的進程 。 Spawn_id照常設置。

變量spawn_out(slave,fd)被設置為對應於pty slave的文件標識符。 它可以使用“close-slala”關閉。

-ignore標誌命名在衍生過程中被忽略的信號。 否則,信號將獲得默認行為。 除了每個信號需要單獨的標誌以外,信號的命名方式與陷阱命令相同。

strace級別
導致在執行之前打印以下語句。 (Tcl的跟踪命令跟踪變量。) level指示調用堆棧要跟踪多遠。 例如,以下命令在跟踪前4個級別的調用時運行Expect ,但是不會在此之下。

期望-c“strace 4”script.exp

-info標誌導致strace返回給定的最近的非信息參數的描述。

stty args
類似於外部stty命令改變終端模式。

默認情況下,控制終端被訪問。 其他終端可以通過追加“請求狀態返回命令的結果”來進行訪問,如果沒有請求狀態並且控制終端被訪問,原始和回顯屬性的先前狀態將以一種形式返回,由命令使用。

例如,參數raw-cooked使終端進入原始模式。 參數-rawcooked使終端進入熟食模式。 參數echo-echo分別將終端設置為echo和noecho模式。

以下示例說明如何暫時禁用回顯。 這可以在其他自動腳本中使用,以避免在其中嵌入密碼。 (請參閱下面的預期提示下的更多討論。)

stty -echo send_user“密碼:”expect_user -re“(。*)\ n”set password $ expect_out(1,string)stty echo

系統參數
給出參數 sh(1)作為輸入,就像它從終端輸入命令一樣。 期待等到殼終止。 sh的返回狀態的處理方式與exec處理其返回狀態的方式相同。

與將stdin和stdout重定向到腳本的exec不同系統不執行重定向(除了由字符串本身指示的重定向)。 因此,可以使用必須直接與/ dev / tty交談的程序。 出於同樣的原因, 系統的結果不記錄在日誌中。

時間戳[args]
返回一個時間戳。 沒有參數時,返回自紀元開始的秒數。

-format標誌引入了一個返回的字符串,但根據strftime的POSIX規則進行了替換。 例如,%a被縮寫星期幾名稱(即星期六)取代。 其他是:

%a縮寫星期幾名稱%A完整星期幾名稱%b縮寫月份名稱%B完整月份名稱%c日期時間如下:Wed Oct 6 11:45:56 1993%d本月的某天(01-31%H小時(00-23)%I小時(01-12)%j日(001-366)%m月(01-12)%M分(00-59)%上午或下午%秒(00-61) %u日(星期一至星期一至星期一為星期幾的第一天)%U週(00-53,第一個星期日為第一星期的第一天)%V星期(01-53,ISO 8601風格)%w日(0- 6)%W週(00-53,第一個星期一是第一個星期的第一天)%x日期時間如下:星期三Oct 6 1993%X時間:23:59:59%y年(00-99) %Y年,如:1993%Z時區(或者如果無法確定,則沒有任何變化)%%光禿禿的百分號

其他%規格未定義。 其他角色將通過未觸及的方式傳遞。 僅支持C語言環境。

-seconds標誌引入了自時代起被用作格式化源的秒數。 否則,使用當前時間。

-gmt標誌強制時間戳輸出使用GMT時區。 沒有標誌時,使用本地時區。

陷阱[[命令]信號]
使未來收到任何給定信號時執行給定命令 。 該命令在全局範圍內執行。 如果命令不存在,則返回信號動作。 如果命令是字符串SIG_IGN,則信號被忽略。 如果命令是字符串SIG_DFL,則信號是系統默認的結果。 信號可以是單個信號,也可以是一系列信號。 信號可以根據信號(3)以數字或符號的方式指定。 “SIG”前綴可以省略。

如果沒有參數(或參數-number),則陷阱將返回當前正在執行的陷阱命令的信號編號。

-code標誌使用命令的返回代碼代替Tcl在命令最初開始運行時要返回的任何代碼。

-interp標誌使命令在命令開始運行時使用活動的解釋器進行評估,而不是在聲明陷阱時進行評估。

-name標誌使陷阱命令返回當前正在執行的陷阱命令的信號名稱。

-max標誌使陷阱命令返回可以設置的最大信號編號。

例如,命令“trap {send_user”Ouch!“} SIGINT”將打印“Ouch!” 每次用戶按^ C。

默認情況下,SIGINT(通常可以通過按^ C生成)和SIGTERM導致Expect退出。 這是由於以下陷阱,當Expect啟動時默認創建。

trap exit {SIGINT SIGTERM}

如果使用-D標誌啟動調試器,則重新定義SIGINT以啟動交互式調試器。 這是由於以下陷阱:

trap {exp_debug 1} SIGINT

通過將環境變量EXPECT_DEBUG_INIT設置為新的陷阱命令,可以更改調試器陷阱。

當然,您可以通過向腳本添加陷阱命令來覆蓋這兩者。 特別是,如果您有自己的“陷阱出口SIGINT”,這將覆蓋調試器陷阱。 如果你想阻止用戶進入調試器,這很有用。

如果您想在SIGINT上定義自己的陷阱,但仍然在調試器運行時陷入調試器,請使用:

if {![exp_debug]} {trap mystuff SIGINT}

或者,您可以使用其他信號捕獲調試器。

陷阱不會讓你重寫SIGALRM的操作,因為這在內部用於Expect 。 disconnect命令將SIGALRM設置為SIG_IGN(忽略)。 只要在後續的spawn命令中禁用它,就可以重新啟用它。

有關更多信息,請參閱信號(3)。

等待[args]
延遲到產生的進程 (或當前進程,如果沒有被命名)終止。

通常等待返回一個四個整數的列表。 第一個整數是等待的進程的PID。 第二個整數是相應的spawn id。 如果發生操作系統錯誤,則第三個整數為-1,否則為0。 如果第三個整數是0,則第四個整數是生成的進程返回的狀態。 如果第三個整數是-1,則第四個整數是操作系統設置的errno的值。 全局變量errorCode也被設置。

其他元素可能會出現在等待返回值的末尾。 可選的第五個元素標識一類信息。 目前,這個元素的唯一可能值是CHILDKILLED,在這種情況下,接下來的兩個值是C風格的信號名稱和簡短的文字描述。

-i標誌聲明進程等待對應於命名的spawn_id(不是進程 ID)。 在SIGCHLD處理程序中,可以通過使用spawn id -1來等待任何產生的進程

-nowait標誌會導致等待立即返回並顯示成功等待。 當進程退出(稍後)時,它將自動消失而不需要明確的等待。

等待命令也可以使用參數“-i -1”等待分叉進程 。 與使用衍生進程不同,該命令可以隨時執行。 無法控制收購哪個流程 。 但是,可以檢查進程 ID的返回值。

圖書館

Expect自動知道Expect腳本的兩個內置庫。 這些由變量exp_library和exp_exec_library中命名的目錄定義。 兩者都是為了包含其他腳本可以使用的實用程序文件。

exp_library包含與體系結構無關的文件。 exp_exec_library包含與架構相關的文件。 根據您的系統,這兩個目錄可能完全是空的。 文件$ exp_exec_library / cat-buffers的存在描述了你的默認/ bin / cat緩衝區。

良好的格式打印

vgrind定義可用於漂亮的Expect腳本。 假設Expect發行版隨附的vgrind定義已正確安裝,您可以將其用作:

vgrind -lexpect文件

例子

很多不太明顯的如何將手冊頁描述的所有內容放在一起。 我鼓勵您閱讀並嘗試Expect發行版示例目錄中的示例。 其中有些是真正的節目。 其他人只是說明某些技術,當然,一對夫婦只是快速入侵。 INSTALL文件可以快速瀏覽這些程序。

期望論文(參見另請參閱)也很有用。 雖然有些論文使用與早期版本的Expect相對應的語法,但隨附的基本原理仍然有效,並且比本手冊頁更詳細。

CAVEATS

擴展可能與Expect的命令名稱相衝突。 例如, send由Tk定義,用於完全不同的目的。 出於這個原因,大多數Expect命令也可用作“exp_XXXX”。 以“exp”,“inter”,“spawn”和“timeout”開頭的命令和變量沒有別名。 如果需要環境之間的兼容性,請使用擴展的命令名稱。

預期對於範圍界定需要相當自由的觀點。 特別是,通過特定於Expect程序的命令讀取的變量將首先從本地範圍中尋找,如果未找到,則在全局範圍中尋找。 例如,這可避免在您編寫的使用期望的每個過程中放置“全局超時”。 另一方面,寫入的變量總是在本地範圍內(除非發布了“全局”命令)。 這導致最常見的問題是在過程中執行spawn時。 在過程之外, spawn_id不再存在,所以產生的過程不再僅僅因為作用域而被訪問。 為這樣的程序添加一個“全球spawn_id”。

如果您無法啟用多次展示功能(即您的系統不支持select(BSD *。*),poll(SVR> 2)或其他類似功能),則Expect一次只能控制一個進程 。 在這種情況下,不要試圖設置spawn_id ,也不應該在生成的進程運行時通過exec執行進程。 此外,您將無法同時期望多個進程(包括一個用戶)。

終端參數對腳本有很大的影響。 例如,如果編寫腳本查找回顯,如果關閉回顯,則腳本會顯示錯誤。 為此,Expect默認強制終端參數。 不幸的是,這會讓其他程序變得不愉快。 例如,emacs shell想要更改“常規”映射:新行映射到換行符而不是回車換行符,並且禁用回顯。 這允許使用emacs編輯輸入行。 不幸的是,Expect不可能猜到這一點。

您可以請求Expect不會覆蓋其默認的終端參數設置,但在編寫此類環境的腳本時,您必須非常小心。 在emacs的情況下,避免取決於回顯和行結束映射等內容。

接受參數的命令放入單個列表( 期望變體和交互 )使用啟發式來確定列表實際上是一個參數還是多個參數。 只有當列表實際上代表一個具有多個嵌入\ n的非空白字符的參數時,啟發式才會失敗。 這似乎非常不可能,但是可以使用參數“-nobrace”來強制將單個參數作為單個參數進行處理。 這可以想像用於機器生成的預期代碼。 同樣,-brace強制將單個參數作為多個模式/動作進行處理。

BUGS

名為“性”的程序(無論是“Smart EXec”還是“Send-Expect”)都是很誘人的,但是良好的意義(或者也許只是清教主義)佔上風。

在某些系統上,當shell被產生時,它會抱怨無法訪問tty,但仍然運行。 這意味著你的系統有一個獲得Expect不知道的控制權的機制。 請找出它是什麼,並將這些信息發回給我。

Ultrix 4.1(至少這裡的最新版本)認為1000000以上的超時等於0。

如果您定義了一個SIGCHLD處理程序,Digital UNIX 4.0A(可能還有其他版本)拒絕分配ptys 。 請參閱grantpt頁面以獲取更多信息。

IRIX 6.0不能正確處理pty權限,因此如果Expect嘗試分配先前由其他人使用的pty,則它會失敗。 升級到IRIX 6.1。

如果未設置TERM,Telnet(僅在SunOS 4.1.2下驗證)會掛起。 這是cron,at和cgi腳本下的問題,它們沒有定義TERM。 因此,你必須明確地設置它 - 哪種類型通常是不相關的。 它只需要設置一些東西! 以下可能足以滿足大多數情況。

設置env(TERM)vt100

如果沒有設置SHELL和HOME,提示(只在BSDI BSD / OS 3.1 i386下驗證)掛起。 這是 cron ,at和cgi腳本下的問題,它們沒有定義這些環境變量。 因此,你必須明確地設置它們 - 哪種類型通常是不相關的。 它只需要設置一些東西! 以下可能足以滿足大多數情況。

設置env(SHELL)/ bin / sh設置env(HOME)/ usr / local / bin

ptys的一些實現被設計為在內核關閉文件描述符後,內核在10到15秒後拋出所有未讀輸出(實際數字取決於實現)。 因此, 預計如程序

產卵日期睡眠20期望

將失敗。 為了避免這種情況,使用exec調用非交互式程序而不是產生 。 雖然這種情況是可以想像的,但實際上我從來沒有遇到過由於這種行為而導致真正的交互式程序的最終輸出會丟失的情況。

另一方面,Cray UNICOS ptys在進程關閉文件描述符後立即丟棄任何未讀輸出。 我已經向Cray報告了這些情況,他們正在努力解決問題。

有時在提示和響應之間需要延遲,例如當tty接口通過查找開始/停止位來改變UART設置或匹配波特率時 。 通常,所有這些都需要睡一兩秒鐘。 一個更強大的技術是重試,直到硬件準備好接收輸入。 以下示例使用兩種策略:

發送“speed 9600 \ r”; sleep 1 expect {timeout {send“\ r”; exp_continue} $提示符}

trap -code不能用於任何位於Tcl事件循環中的命令,如睡眠。 問題是,在事件循環中,Tcl放棄了來自異步事件處理程序的返回碼。 解決方法是在陷阱代碼中設置一個標誌。 然後在命令後立即檢查標誌(即睡眠)。

expect_background命令忽略-timeout參數,並且通常沒有超時的概念。

"預期提示"

有一些關於Expect的內容可能不直觀。 本節試圖用一些建議來解決其中的一些問題。

常見的期望問題是如何識別shell提示。 由於這些定制方式因不同的人和不同的shell而不同,因此在不知道提示的情況下,可移植性自動化rlogin可能會很困難。 一個合理的慣例是讓用戶在環境變量EXPECT_PROMPT中存儲一個正則表達式來描述他們的提示(特別是它的結束)。 可以使用類似下面的代碼。 如果EXPECT_PROMPT不存在,代碼仍然有正常運行的良好機會。

設置提示符“(%|#| \\ $)$”;#默認提示符catch {set prompt $ env(EXPECT_PROMPT)} expect -re $ prompt

我鼓勵你寫預期模式,包括任何你期望看到的結局。 這避免了在看完整個事情之前回答問題的可能性。 另外,雖然你完全可以在看到它們之前回答問題,但如果你提前回答,你的回答可能會在問題中間回顯。 換句話說,最終的對話將是正確的,但看起來很混亂。

大多數提示最後都包含空格字符。 例如,來自ftp的提示是'f','t','p','>'和。 要匹配此提示,您必須考慮每個這些字符。 不包括空白是一個常見的錯誤。 明確地填入空格。

如果使用X *形式的模式,*將匹配從X末尾接收到的所有輸出到最後一次接收到的輸出。 這聽起來很直觀,但可能有點令人困惑,因為短語“最後收到的東西”可能因計算機的速度以及內核和設備驅動程序的I / O處理而異。

特別是,當實際上大多數節目一次產生一行輸出時,人類傾向於看到節目輸出以大塊(原子)方式到達。 假設情況如此,前一段的模式中的*可能只與當前行的結尾相匹配,即使似乎有更多,因為在匹配時,這是所有已收到的輸出。

除非你的模式特別說明它,否則期望無法知道進一步的輸出即將到來。

即使取決於線路緩衝是不明智的。 不僅程序很少會對他們所做的緩衝類型作出承諾,而且系統消化不良可能會破壞輸出線,從而使線在看似隨機的地方斷裂。 因此,如果在編寫模式時可以表示提示的最後幾個字符,那麼這樣做是明智的。

如果您正在等待程序的最後一個輸出中的模式,並且該程序會發出其他內容,您將無法使用timeout關鍵字來檢測該模式。 原因是期望不會超時 - 相反,它會得到一個eof指示。 改為使用它。 更好的是,同時使用兩者。 這樣,如果該線路四處移動,則不必編輯線路本身。

換行符通常會在終端驅動程序輸出時轉換為回車符,換行符序列。 因此,如果你想要一個明確地匹配printf(“foo \ nbar”)這兩行的模式,你應該使用模式“foo \ r \ nbar”。

通過expect_user從用戶讀取時發生類似的翻譯。 在這種情況下,當您按回車時,它將被轉換為換行符。 如果Expect將其傳遞給一個將其終端設置為原始模式(如telnet)的程序,則會出現問題,因為該程序需要真正的返回。 (有些程序實際上是寬容的,因為它們會自動將換行符轉換為返回值,但大多數程序不會)。不幸的是,無法確定程序是否將其終端設置為原始模式。

解決辦法是使用命令“stty raw”,這將停止翻譯。 但請注意,這意味著您將不再獲得熟悉的行編輯功能。

交互隱式設置你的終端為原始模式,所以這個問題不會出現。

Expect腳本中存儲密碼(或其他私人信息)通常很有用。 這是不推薦的,因為任何存儲在電腦上的東西都容易被任何人訪問。 因此,交互式地從腳本中提示密碼是比從字面上嵌入它們更聰明的想法。 儘管如此,有時這種嵌入是唯一的可能性。

不幸的是,UNIX文件系統沒有創建可執行但不可讀的腳本的直接方式。 支持setgid shell腳本的系統可以間接模擬如下:

像往常一樣創建Expect腳本(包含秘密數據)。 使其權限為750(-rwxr-x ---),並由一個受信任的組(即允許讀取它的組)擁有。 如有必要,請為此創建一個新組。 接下來,創建一個具有與之前相同的組的權限2751(-rwxr-s-x)的/ bin / sh腳本。

結果是一個可以被任何人執行(並閱讀)的腳本。 當被調用時,它運行Expect腳本。

"另請參閱"

Tcl (3), libexpect (3)
“Exploring Expect:基於Tcl的工具包,用於自動化交互式程序” ,Don Libes,第602頁,ISBN 1-56592-090-2,O'Reilly and Associates,1995。
“期望:治愈那些無法控制的交互性的適應”,Don Libes, 1990年夏季刊,美國加利福尼亞州阿納海姆1990年6月11 - 15日的會議論文集。
.I“使用期望自動化系統管理任務”,由Don Libes於1990年10月17 - 19日在科羅拉多州科羅拉多斯普林斯舉行的1990 USENIX大型安裝系統管理會議論文集中提供。
.I“Tcl:一種可嵌入的命令語言”作者John Ousterhout 1990年美國華盛頓特區1990年1月22 - 26日在美國華盛頓舉行的會議論文集“我期望:控制交互式程序的腳本”,由Don Libes,Computing Systems ,Vol。 4,No.2,加利福尼亞大學出版社,1991年11月.I。“回歸測試和一致性測試交互式程序”,由Don Libes出版,1992年夏季刊USENIX Conference,135-144頁,San Antonio,TX, 1992年6月12日至15日..我“Kibitz - 連接多個交互式程序”,作者:Don Libes,Software - Practice&Experience,John Wiley&Sons,West Sussex,England,Vol。

1993年5月第23卷第5期.I'Teporger for Tcl Applications“,Don Libes,1993年Tcl / Tk Workshop,1993年6月10 - 11日加利福尼亞州伯克利的論文集。

作者

Don Libes,國家標準與技術研究院

致謝

感謝Tcl的John Ousterhout和Scott Paisley的靈感。 感謝Rob Savoye為Expect的自動配置代碼。

HISTORY文件記錄了期望的大部分演變。 它使有趣的閱讀,並可能讓你進一步洞察這個軟件。 感謝其中提到的人誰給我錯誤修復,並給予其他幫助。

Expect的設計和實施部分由美國政府支付,因此屬於公共領域。 然而,如果使用這個程序和文檔或者其中的一部分,作者和NIST希望得到信任。