Expect 手冊 中文版

                     Expect 手冊 中文版
本文由gunman翻譯,在此感謝~
EXPECT(1)
名字:
Expect-----能與交互式程序進行“可程序化”會話的腳本語言
大綱:
        (命令選項概述)
        expect [ -dDinN ] [ -c cmds ] [ -[f|b] ] cmdfile ] [ args ]
概述:
  
Expect是一種能夠按照腳本內容裏面設定的方式與交互式程序進行“會話”的程序。根據腳本內容,Expect可以知道程序會提示或反饋什麼內容以及
什麼是正確的應答。它是一種可以提供“分支和嵌套結構”來引導程序流程的解釋型腳本語言。另外,還可以在隨時需要的時候把控制權交給用戶,然後再還給腳
本。
    ExpectK是Expect和Tk的混合體。它就按照Expect和Tk的方式運行。Expect也可以直接嵌入到C或是C++程序中(這種情況是不涉及Tcl解釋)。請看libexpect(3).
    Expect的名字是從被UUCP(UNIX到UNIX的拷貝),Kermit(一種文件傳輸協議,
由哥倫比亞大學設計)和一些其他Modem控制等程序設計思維大衆化的“send/expect”時序理念中得出的。不像UUCP,Expect已經被廣
泛應用於很多你可以想像的到的程序和任務當中了。
Expect還能同時和多個程序交互。
    例如:下面是一些Expect可以做到的事情
1)讓你的計算機呼叫你,這樣你可以不用付呼叫費。
2)啓動一個遊戲(例如:rogue),如果不是最佳配置,則一直重新啓動,直到是最佳配置爲止。然後把控制權轉交給你。
3)運行fsck的時候,用”yes”或是”no”來回應fsck的交互問題。在沒有預設答案標準的情況下把控制權返還給你。
4)連接到另一個網絡或是BBS站點,自動收取你的郵件,就像郵件是發往你的當地系統一樣。
5)在執行rlogin,telnet,tip,su,chgrp等等命令的時候保存“環境變量”,“當前目錄”或是其他一些信息。
有很多原因致使Shell不能完成這樣的任務(你自己可以試試看)。而這一切對於Expect
來說都是可以的。一般情況下,當一個程序需要程序與用戶進行交互的時候就需要用到Expect。還需要的一個前提是這種交互必須能程序化(例如:循環結
構,選擇結構等等,個人認爲必須是有規律可循的)。如果需要的話,Expect還能把控制權返還給用戶。同樣,用戶也可以在任何時候把控制權還給腳本程
序。
用法:
    Expect通過讀取cmdfile(命令文件)來執行一系列指令。只要系統支持“#!“,在Script腳本文件的首行標明“#!/usr
/local/bin/expect –f“,並賦予腳本文件可執行權限,執行腳本文件就可以(隱含方式或是默認)調用Expect。
    當然,上面的路徑必須正確地指明Expect解釋程序的位置。/usr/local/bin只是一個例子。
    -c 選項用來標明需要在執行腳本內容之前來執行的命令。
      這條命令(-c選項後的命令)應該用引號括起來,以免在執行時被shell分開解釋。
      -c選項可能會被反覆使用。多條命令可以使用同一個”-c”,命令之間需要用分號隔開。這些命令會按照它們出現的先後順序執行。(在Expectk中,”-c”相當於”-command”)。
    -d 選項允許輸出調試性信息。這些信息主要報告像expect和interact等命令執行時的內部行爲。這個選項與寫在腳本開頭的
”exp_internal
1”具有同樣的效果,同時還會打印出Expect的版本。(strace命令用在跟蹤變量聲明,trace命令用於跟蹤變量的賦值)(在Expectk
中,”-d”相當於”-diag”)
    -
D選項開啓交互調試器。後面必須跟有一個整數值作爲參數,當值爲非零或是按下CTRL+C的時候(或是遇到斷點,或是在腳本中恰好出現其他的調試語句),
調試器會在進行下一次Tcl Procedure前取得控制權。想了解更多信息請參見README文件或是下面的SEE
ALSO。(在Expectk中,這個選項相當於”-Debug”)。
    - f 選項指明從哪個文件中讀取命令。這個選項是可選的,因爲只有當使用”#!”時它纔有可能被用到。而其他選項可以寫在命令行中。(在Expectk中,它相當於”-file”)。
    默認情況下,命令文件是全部讀入內存一併執行的。但有些時候需要每次只讀一行。例如:stdin(標準輸入)就是這樣讀取的。如果強制任意文件以這種方式(每次讀一行)執行的話就使用”-b”選項。(在Expectk中,它相當於”-buffer”)。
    如果”-“被一個文件名替代,那麼腳本就會用讀指定文件的方式來替代從標準輸入讀的方式。(例如:”./ -“就表示從一個名爲”-”的文件中讀所需的信息)。
    -i
選項使Expect能交互式的提示輸入命令,而不是從文件中讀取。在遇到文件尾或是執行了exit命令時,提示輸入命令終止。要了解更多信息請參見下面的
interpreter。-i
選項是假設既不是從一個命令文件讀,也沒有使用-c選項。(在Expectk中,它相當於”-interactive”)。
    -- 是用來爲劃定選項尾的。當你需要像使用選項一樣傳一個參數,但希望這個參數不要被當作選項解釋時,就需要用到這個選項。當阻止其他選項時,可以把它放在”#!”行中。例如:下面的例子會讓所有參數(包括腳本文件名)都存儲在argv中。
    #!/usr/local/bin/expect –
注意:當在”#!”行中使用參數時,必須遵守getopt(3)和execve(2)的規定。
    $exp_library下如果有expect.rc這個文件的話,它會自動被加載爲資源文件(應該是類似於標準配置文件,像用戶根目錄下
的.bash_profile文件一樣)。除非使用-N選項取消自動加載。(在Expectk中,它相當於”-NORC”)。這個文件被加載後,緊接着用
戶根目錄下的.expect.rc(~/.expect.rc)會被加載。除使用-n選項取消。如果定義了環境變量DOTDIR,那麼它被認爲是存放
有.expect.rc文件的目錄。然後從這個目錄中讀取.expect.rc文件。(在Expectk中,它相當於”-norc”)。這些加載配置文件
的動作是出現在執行完-c選項指定的命令之後。
    -v 選項用來打印出版本號,然後退出。(在Expectk中的相應選項是-version)。
    可選的參數匯成一列,存放在變量argv中。Argc被初始化爲argv的長度(變量個數)。Argv0被設置爲腳本名稱(or binary if no script is used)。例如:下面的例子打印出腳本的名稱和前三個參數。
    Send_user “$argv0 [lrang $argv 0 2 ]\n”
命令:
    Expect使用Tcl語言(Tool Command Language).Tcl提供諸如流控制,表達式值和一些其他的特性。像遞歸調用,定義函數等等。在這裏用到的沒有說明的命令都是Tcl命令。
    Expect支持一些額外的命令。下面具體描述。除非另外聲明,否則命令返回空字符串。命令按字母順序排序,這樣便於查找。僅管如此,初學者還是覺得按照”spawn , send , expect , interact”這種方式來讀比較容易。
    注意,Exploring Expect這本書中提供了關於”Expect和Tcl”的介紹.這本Manpage手冊中也提供了一些例子.但數量有限,因爲這本是做爲入門的教材手冊使用的.
    在本手冊中,以E開頭的是指Expect程序,小寫e開頭的是指expect命令.
    close [-slave] [-onexec 0|1] [-i spawn_id]
  
關閉與當前進程的連接.大多數交互程序會在它們的stdin(標準輸入)中檢測到EOF(文件尾),然後退出.所以通常close也有能力殺死進
程.-i選項指定了要殺死的對應於spawn_id的進程.expect和interact都能檢測到當前程序的退出,並隱含的執行一個關閉.如果你通過
執行”exec kill $pid”來殺死進程的話,那麼你就需要再顯式的調用一下close.
    -onexec選項用來確定spawn_id在開始新的spawned
process(我將其翻譯爲監測進程)時是被關閉還是要被覆蓋.如果想保持這個spawn_id打開的話,那麼後面的參數需要設爲0.一個非零值將會使
spawn_id關閉,並可以將這個spawn_id用於新的進程(默認行爲).-slave選項是用來關閉從屬進程.(參見spawn
-pty)。如果在連接中止的時候,從屬進程還打開的話,那麼它將自動關閉。不管進程是顯式的調用或是隱式的被中止,你都需要調用wait命令來清理進程
執行的殘餘。Close不會調用wait。因爲在關閉進程的時候,並不能保障它“正常退出”(個人認爲,可能是指退出時做相應的清理工作)。要了解更多的
信息,請參見wait命令。
    debug [[-now] 0|1]
  
控制Tcl調試器以步進方式執行語句,設置斷點等等。在沒有參數的情況下,如果調試器沒有運行,返回1,否則返回0。用1做參數時,啓動調試器,用0做
參數時,停止調試器。如果連同-now一起使用的話,調試器將立即啓動(也就是說,在debug命令當中)。否則調試器會在執行下一條語句的時候啓動。
    調試命令不會改變任何的traps。可以參見以-D選項啓動Expect(參見上面)
    要了解更多關於debugger的內容,請參見README文件和下面的SEE ALSO。
    disconnect
從終端關閉與一個克隆進程的連接,但讓它在後臺繼續運行。這個進程將被賦予爲單獨的進程組(如果可能的話)。標準I/O被重定向到/dev/null。下面的代碼使用disconnect命令使腳本在後臺繼續運行。
    if [fork]!=0 exit
        disconnect
    下面的腳本需要讀取一個密碼,然後每小時執行一次,每次執行的時候都要求輸入密碼。腳本提供了所需的密碼,所以你只需輸入一次就可以了。(參見能關閉回顯的終端命令)。
    send_user "password?\ "
        expect_user -re "(.*)\n"
        for {} 1 {} {
            if [fork]!=0 {sleep 3600;continue}
               disconnect
               spawn priv_prog
               expect Password:
               send "$expect_out(1,string)\r"
               . . .
               exit
        }
用這種方式,而不是用Shell後臺方式來執行程序的好處是,用disconnect可以在關閉前保存終端參數,然後把它們應用於新的終端中。如果使用&的話,Expect沒有機會讀取終端參數,因爲在Expect取得控制權的時候,終端已經退出了。
    exit [-opts] [status]
  
使Expect退出或是準備退出。-onexit選項使下一個參數做爲退出的句柄被使用。沒有參數時,返回當前的退出句柄。-noexit選項使
Expect準備退出,而不是把控制權暫時返還給系統。用戶定義的退出句柄和Expect內部的句柄都是以同樣的方式被返回。接下來將不再執行
Expect命令。這在Tcl擴展環境下執行Expect時非常有用。保留當前的解釋器(在Tk環境中的主窗口)以清除其他的Tcl擴展。如果
Expect再次調用exit(這有可能發生),不會返回句柄。退出時,全部連接將關閉,關閉的動作會被監測的進程檢測爲“到文件尾”。exit只按照正
常exit(2)的中的語句來執行,不會引發其他的動作。因此監視的進程如果沒有檢測到“到文件尾”的話,會繼續執行。(能檢測更多的情況是很重要的。例
如:什麼樣的信號會發給監測進程,但這些是由系統決定的,它們放在exit(3)的文檔中)。如果被監測的進程繼續運行的話,將會被init繼承。當前的
狀態信息將做爲Expect的退出信息返回(如果沒有指明的話,返回信息爲0)。退出命令在腳本程序執行的最後才自動隱含的調用。
    Exp_continue [-continue_timer]
    這個命令可以使expect繼續執行而不是正常的返回.默認情況下,exp_continue會重高超時時鐘,-continue_timer選項會阻止時鐘重新計數(連續計數).
    Exp_internal [-f file] value
  
如果是value非零的話,使接下來的命令將調試信息輸出到Expect和標準錯誤輸出.如果是0的話,輸出的信息將會被屏蔽.調試信息包括收到的每條
信息和每次嘗試用當前輸出與腳本中的模式相匹配的信息.如果設置了輸出文件,那麼正常的和調試的信息都會被寫到這個文件當中.(忽略上面value選項的
值).任何之前打開的調試輸出文件將會被關閉.-info選項使exp_internal返回最近關於non-info參數的描述.
    Exp_open [args] [-I spawn_id]
    它返回對應於原始spawn
id的文件描述符.這樣這個文件描述符就可以被使用了,就好像這個文件是被Tcl的open指令打開的一樣.(這個spawn
id將不再使用,wait指令將不能用在這個進程.).-leaveopen選項使spawn id保持打開,以便供Expect命令使用.
    Exp_pid [-i spawn_id]
    它將返回對應於當前被跟蹤進程的ID.如果使用-i選項,將返回對應於指定的spawn id的進程ID.
    Exp_send
        它是send的別稱
    Exp_send_error
        它是Send_error的別稱
    Exp_send_log
        它是Send_log的別稱
    Exp_send_tty
        它是Send_tty的別稱
    Exp_send_user
        它是Send_user的別稱
    Exp_version [[-exit] version]
它用於確保腳本程序與當前的Expect兼容。在沒有參數的情況下,返回當前Expect的版本.這個版本就會編譯到腳本中.如果你確切的知道你的腳本程
序不需要最新版本的特性,可以指定一個以前的版本。   
  
版本號由三個由句點分隔的數字組成.第一個是主序號.對應某一主序號版本的Expect寫的腳本程序,在不同主序號版本的Expect環境下基本不能正
常運行.exp_version在主版本不同的情況下會返回一個錯誤.第二個數字是次版本號.編寫腳本的Expect的次版本號如果比當前的Expect
大的話,可能會用到一些新的特性,在當前的環境下可能不能正常運行.exp_version會在當主序號相同,但次序號比當前Expect版本大的時候返
回一個錯誤信息.第三個數字在Expect的版本比較中沒有多大作用.它只是當發行版有任何變化的時候會增加.比如說增加一些新的文檔或是做了優化.當升
級到一個新的次版本號時,這個數字會被初始化爲零.如果使用了-exit選項,Expect會在當前的版本過期的時候打印一個錯誤信息,然後退出.
    expect [[-opts] pat1 body1] ... [-opts] patn [bodyn]
    等待直到被監視進程的輸出與設定的模式相匹配,或是一個指定的時間過後,或是遇到文件尾.如果最後的body是空的,那麼它將被忽略.最近的
expect_before設定的模式會在其他模式之前被隱含地使用.最近的expect_after設定的模式將在所有其他模式匹配完後才被調用.如果
整個Expect命令的參數超過一行,這個參數可能被分爲多行,各行之間用一個”\”連接,以防被分開解釋.在這種情況下,Tcl解釋器通常會置換掉”
\”.如果一個模式設定爲eof.則相應的語句被在當達到文件尾的時候執行.如果一個模式設定爲timeout,那麼相應的語句會在超時時執行.如果沒有
設定timeout對應的執行語句,將會在timeout時隱含執行空指令.即不執行任何語句.默認的超時時鐘設的是10秒,但可以自己設定.通過
”set timeout
30”,可以將超時時鐘設定爲30秒.如果設定爲-1的話,那麼超時時鐘將是無窮大,如果一個模式設定爲default,那麼相應的語句將會在遇到文件尾
或是超時時執行.如果觸發了相應的模式,則此模式對應的語句將會被執行.Expect返回語句執行的結果(或是在沒有模式觸發的情況下是空字符串).在多
種模式匹配的情況下,第一個匹配的模式對應的語句將被執行.
  
每次出現新的輸出的時候,它們都會依次匹配相應的模式.因此,如果你想測試匹配是否成功,可以把最後一個模式設定爲肯定會出現的東西,例如一個提示符.
在沒有提示符的情況下,你需要使用一個timeout模式。模式被定義爲三種類型.默認情況下,模式被定義爲Tcl的string
match(字符串匹配)指令.(這些模式很像C
Shell中的正則表達式,它們通常被用來做模糊匹配).-gl選項保護那些可能被認爲是Expect的選項的模式匹配字符串。以”-”開頭的所有模式匹
配字符串都需要這樣保護起來。(因爲默認情況下,以”-”開頭的字符串都被保留起來做爲將來的選項)。例如:下面的代碼期望一個正確的登錄.(注意下面的
abort是一個已經在腳本的其他位置定義好的函數)
        expect {
                     busy               {puts busy\n ; exp_continue}
                     failed             abort
                     "invalid password" abort
                     timeout            abort
                     connected
                 }
  
在第四行需要使用引號,因爲它包含了一個空格.如果不用引號把模式括起來的話,它會被分別解釋爲模式與執行函數.執行同樣動作的其他模式同樣需要把執行
函數的名稱寫出來(像其他兩個執行”abort”函數的模式),如果使用regexp-style模式的話(看下面的例子),更多關於建立glob-
style模式的信息請參見Tcl手冊.regexp模式以-re開頭.上面的例子可以用regexp模式改寫成下面的代碼:
        expect {
                     busy       {puts busy\n ; exp_continue}
                     -re "failed|invalid password" abort
                     timeout    abort
                     connected
                 }
兩種類型都可以被正確匹配。這就是說設置的類型可以不用是整個字符串。可以只匹配頭部或是尾部(就假設其他部分也匹配一樣)。用^來匹配字符串頭部。
用$來匹配字符串尾部。如果你不希望等待直到字符尾,你可以在監視進程回顯字符的中間時刻結束響應。雖然仍能打印出正確的結果,但最後的輸出可能看上去有
點混亂。因此如果能夠詳細描述預期的字符串尾部的話,還是鼓勵使用$來匹配尾部。在許多編輯器中,^和&分別表示首行和尾行。因爲Expect不
是基於行緩衝的程序。所以這兩個字符分別用來表示當前匹配緩衝區中的頭數據和尾數據。-ex使模式進行精確匹配。這時,不對*,^等字符進行解釋(但還是
要遵守Tcl的規則)。Expect patterns are always unanchored.
  
-nocase選項使輸出中的大寫字符也按小寫字符匹配。模式匹配字符串本身改變。在讀取輸出進行匹配時,超過2000字符將會強制將前面的字符丟棄。
這個數目可以通過match_max來改變。(但太大的數目會降低匹配的效率)。如果patlist是full_buffer,則在收到
match_max個字節而沒有相應的模式匹配成功時,執行full_buffer所對應的語句。不管是否使用了關鍵字full_buffer,丟棄的字
符都會被寫到expect_out緩衝區中。如果patlist是關鍵字null。並且空是有效字符(通過remove_nulls指令訪問),如果輸出
是一個單個的ASCII碼0,那麼null相對應的語句將被執行。通過glob或是regexp模式是不能來匹配0字符。        
在匹配字符串時(或是遇到文件尾,或是緩衝區滿full_buffer),任何匹配的或是前面沒有匹配的輸出都會被保存在expect_out緩衝區中。
匹配到的9個字符分別被放到expect_out(1,string)至expect_out(9,string)中。如果在模式前使用了
-indices選項,那麼,這10個字符的開始字符和結尾字符在字符串中的位置被分別存放在變量expect_out(X,start)和
expect_out(X,end)中。其中X是自然數(應該是0到9)。0(expect_out(0,*))是指整個匹配的字符串,它可以用於
glob模式,也可以用於regexp模式。例如:如果一個進程的輸出爲“abcdefgh\n”,那麼expect
“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).與匹配輸出相對應的spawn
id被存儲在expect_out(spawn_id)中.
    -timeout 選項使得Expect使用選項後面的數值做爲超時時間,而不是timeout變量中設置的時間.   
  
默認情況下,設定的模式只與當前進程的輸出進行匹配.-i選項使得指定spawn_id或是spawn_id列的輸出與下面列出的所有模式進行匹配(直
到下一個-i選項爲止).spawn_id列要麼是用空格分隔的一列spawn_id,要麼是用變量存儲的這要一列spawn_id.例如,下面的例子
中,當前進程與”connected”進行匹配,由變量$proc2指定進程與”busy”,”failed”,”invalid
passowrd”進行匹配。
        expect {
                     -i $proc2 busy {puts busy\n ; exp_continue}
                     -re "failed|invalid password" abort
                     timeout abort
                     connected
              }
  
全局變量any_spawn_id的值是在當前expect中所有-i選項定義的spawn_id進程列的總和.它用來使這些spawn_id進程列與
模式進行匹配。在一些-i選項中可能只給出了spawn_id列,但沒有給出相應匹配模式.(例如,-i選項緊接下來就是另一個-i選項).那麼這些
spawn_id列將會去匹配與any_spawn_id相對應的模式.   
    -i選項還可以定義一個全局變量,裏面存儲着spawn_id列.當變量內容發生變化時,它會被重新讀取.這樣就可以在程序執行的時候改變I/O源.以這種方式提供的spawn_id被稱爲”indirect spawn_id”.
  
Break和continue使流程(例如:for結構,proc函數)按照正常的順序執行.exp_continue使expect繼續執行而不是像
通常一樣返回.這對於避免explicit
loops(不執行以後有語句,直接進入下一次循環)和重複的語句很有用.下面的例子是一個自動rlogin的代碼片斷.exp_continue的使用
避免了在rlogin揭示輸入密碼的時候的再寫一個重複的expect語句.(需要等待第二次提示)
        expect {
                     Password: {
                         stty -echo
                         send_user "password (for $user) on $host: "
                         expect_user -re "(.*)\n"
                         send_user "\n"
                         send "$expect_out(1,string)\r"
                         stty echo
                         exp_continue
                     } incorrect {
                         send_user "invalid password or account\n"
                         exit
                     } timeout {
                         send_user "connection to $host timed out\n"
                         exit
                     } eof {
                         send_user \
                             "connection to host failed: $expect_out(buffer)"
                         exit
                     } -re $prompt
                 }
  
例如,下面的代碼使用戶可以在任務完全自動化的情況下,還能引導人機交互.這種情況下,終端被設置成原始狀態.如果按下”+”,那麼一個變量的值增加,
如果按下”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的工作方式相同.在expect和expect_after能同時匹配的情況下.進程與expect命令下面的模式進行匹配.想了解更多的信息請參見expect_before.
    Expect_background [expect_args]
  
它和expect有一樣的參數列表.但不同的是它是立即返回.一旦有新的輸入到達時就開始進行模式匹配,timeout和default兩個模式對於
expect_background來說沒有意義,它們會被隱含忽略.否則,expect_background會像expect一樣調用
expect_before和expect_after的模式匹配.
  
當expect_background在執行模式匹配時,對應於這個spawn_id的後臺進程將被阻塞.當執行完成時,後臺進程被解開.在後臺進程被
阻塞期間,還可以在前臺以同樣的spawn_id執行一個expect腳本.但在非阻塞情況下是不可能這樣做的.在用同一個spawn_id聲明一個新的
expect_background時,前一個就會被自動刪除.聲明一個沒有匹配模式的expect_background將會使相應的spawn_id
失去在後臺匹配模式的能力.
    Expect_before [expect_args]
  
它和expect具有相同的參數列表.但不同的是它立即返回.相同spawn_id最近的expect_before下的匹配模式會自動隱含的加載到下
面的expect命令中.如果其中一個模式匹配成功了,就好像匹配的模式是列在expect命令本身下面一樣.如果expect_before和
expect的模式同時匹配,那麼將使用expect_before.如果沒有相應的匹配列出來,那麼這個spawn_id將不進行任何模式匹配的動作.
  
除非使用-i選項強制聲明,否則expect_before的模式將與執行expect_before命令時對應的spawn_id的進程輸出進行匹配
(而不是有模式匹配成功時的spawn_id).-info選項會返回當前模式的詳細信息.默認情況,它會報告當前的spawn_id的信息。也可以通過
指定spawn_id來顯示指定spawn_id的信息.
例如:    expect_before –info –I $proc
    這樣最多返回一個spawn_id的詳細信息. The flag -indirect suppresses direct spawn ids that come only from indirect specifications.
    -all選項使expect_before報告所有spawn_id的信息,而不是單個spawn_id的信息。
    expect_tty [expect_args ]
  
和expect的用法很像,但它是從/dev/tty讀取字符串(例如:用戶的擊鍵)。默認情況下,讀是工作在精加工緩衝模式下的。因此,每行之後必須
以回車結尾,這樣expect才能分別識別它們。讀模式(例如行緩衝,等等)可以通過stty命令更改(參見下面的stty命令)
    expect_user [expect_args]
  
和expect的用法很像,但它是從stdin(標準輸入)讀取字符串(例如:用戶的擊鍵)。默認情況下,讀是工作在精加工模式下的。因此,每行之後必
須以回車結尾,這樣expect才能分別識別它們。讀模式(例如行緩衝,等等)可以通過stty命令更改(參見下面的stty命令)。
    Fork
  
創建一個新進程。這個新進程是當前進程的完整拷貝。成功時,會返回0給新進程,返回新進程的ID給當前進程。失敗時(失敗的原因可能是資源匱乏,如交換
分區,內存不足等),返回一個-1給當前進程,沒有新進程創建。複製的新進程和它的父進程一樣通過exit命令退出。複製的新進程允許寫日誌文件。如果不
屏蔽大多程序的debugging(調試)和logging(寫日誌)功能,結果(個人認爲:輸出結果或是日誌)看起來會顯得有點混亂。在多個用戶的情況
下,即使是很短暫的pty執行結果,看起來也會很讓人混亂迷惑。因此,在監視某個進程(個人認爲是執行spawn)之前執行fork更好一點。
    interact [string1 body1] ... [stringn [bodyn]]
  
返回當前進程的控制權給用戶。所以擊鍵會被傳給當前進程(就像平時操作一樣)。當前進程的stdout和stderr也會返回(個人認爲:可能在腳本執
行時,標準輸出和標準錯誤輸出是被重定向到Expect的,因爲執行spawn之後,expect會等待進程的輸出,包括錯誤輸出)。String-
body被指定爲參數。在這種情況下,當有指定的string輸入時,對應的body就會被執行(默認情況,string不會被傳給當前進程)。如果沒有
最後的body部分,那麼將執行interact命令。如果整個interact語句參數過長,超過一行,這些參數會用反斜線連接,分隔在多行,這樣避免
了語句在執行時被隔斷。這種情況下,在Tcl進行語法解釋的時候會忽略這些反斜線,把這多行做爲一條語句來執行。例如,下面的代碼舉例說明了以
string-body方式執行interact命令。String-body是這樣設定的:當你按下Ctrl+Z時,Expect
將掛起,按下Ctrl+A時,用戶將會看到屏幕顯示“you typed a control
A”,並且也向當前進程發送一個Ctrl+A。當用戶按下$時,用戶會看到屏幕上顯示系統日期。按下Ctrl+C
時Expect將退出。如果輸入”foo” ,用戶將在屏幕上看到“bar”,如果輸入~~,那麼Expect解釋器交互執行。
        set CTRLZ \032
                 interact {
                     -reset $CTRLZ {exec kill -STOP [pid]}
                     \001   {send_user "you typed a control-A\n";
                             send "\001"
                            }
                     $      {send_user "The date is [exec date]."}
                     \003   exit
                     foo    {send_user "bar"}
                     ~~
                 }
    在string-body中,字符是按string在string-body中出現的順序匹配的。
  
在不清楚餘下的字符是什麼的情況下,只是部分匹配的字符是不會被髮送到當前進程的。如果在獲得了餘下的字符之後,整個字符串沒有相應的string-
body可以匹配(也就是說整個字符串在string-body中,沒有對應相同的string),除了上面說的匹配字符外,也沒有其他更多的匹配(個人
理解:比如整個字符xxxbbccada.第一次提到的匹配字符xxxbb,string-body中有兩個對應的
string:string1=xxxbb,string2=xxxbbcc,那麼也就是說整個字符是沒有相應的string與之匹配,如果只有
string1,沒有string2,那也就是“沒有更多的匹配”,只有xxxbb會發送到當前進程,如果存在string2,那麼我們最好把
string2放在string1前面,這樣可以先在匹配string2,如果輸出字符串中,沒有相應的xxxbbcc,然後再去匹配string1。也
就是說把“最大匹配”放在前面),那麼只有匹配的字符會發給當前進程。因此,我們可以把“部分匹配”放在後面,如果整個字符(或是“最大字符”)匹配失
敗,我們再進行“部分匹配”。默認情況下,string匹配必須是精確完全匹配。(與之相反,expect命令默認使用glob-style模式)。
-ex選項保證那些可能被解釋成interact選項的string能被正確執行。任何以”-”開頭的string都需要使用-ex。(所有以”-”開頭
的字符將被做爲選項)
    -re選項強制string按regexp模式解釋。這種情況下,像expect會把它的輸出存儲在變量expect_out裏面一
樣,interact匹配的字符串也會在存儲在變量interact_out中。-indices選項的作用也和expect中的一樣。Eof模式列出了
在遇到文件尾的時候要執行的語句。一個單獨的eof模式可能跟在-output選項後面,這樣當寫輸出遇到文件尾的時候,就會觸發eof模式,執行相應的
語句。默認的eof行爲是返回,所以執行interact命令時,在遇到文件尾就是返回。Timeout模式介紹了超時(以秒爲單位)的概念,並列出了
(超時)連續數秒沒有讀取到字符後的執行語句。Timeout作用於最近指定的進程。**這裏沒有默認的timeout,特殊變量
timeout(expect命令裏面使用的)對這裏的timeout模式沒有影響。**例如,下面的命令可以用於自動退出用戶,他們在一小時之內沒有輸
入任何字符,卻一直收到系統消息。
interact -input $user_spawn_id timeout 3600 return –output  $spawn_id
    如果模式爲關鍵詞null,而且null是允許的(通過remove_null命令),則在輸出中如果出現單個的ASCII
0,那麼null對應的語句將被執行。在glob和regexp模式下是不可能完成的。在模式前加上-iwrite選項,將會把匹配成功(或是遇到文件
尾)的進程的spawn_id賦值給變量interact_out(spawn_id)。Break和continue會使控制結構(for循環,子函數
等等)按照正常的方式運行,但return會使interact把信息返回給它的調用函數。Inter_return會使它的調用函數返回。例如,如果一
個子函數foo調用了inter_return,在執行inter_return時,子函數foo會返回。(這就是說,當interact交互式調用解釋
器時,如果輸入return,那麼交互還將繼續,如果輸入inter_return,那麼interact將返回)
    在interact執行過程中,終端工作在“原始狀態”下,這樣所有字符都將發送給當前進程。如果當前進程沒有捕獲到工作流程的信號,那麼按下
Ctrl+Z會使其中止。如果想重啓這個進程,可以給它發送一個“繼續”信號(如執行:"kill  -CONT
"),如果你真想給當前進程發送一個“中止”信號,你可以考慮先監視csh,然後再啓動你的程序。也就是說,如果你想發送中止信號
給Expect,首先要調出解釋器(可能是按一下ESC鍵),然後按下Ctrl+Z。
  
爲了避免進入解釋器,交互式的執行命令,string-body可以用做“速記”,當string-body對應的body執行的時候,使用的前一個終
端模式。爲了程序的執行效率,默認情況下,終端使用原始狀態。-reset使終端恢復到interact執行以前的狀態(總是“精加工”狀態)。注意的
是,在進行終端模式轉換的時候,此時輸入的字符可能丟失(在一些系統上,會出現這種
糟糕的現象)。最好在你必須使用”精加工”模式再使用-reset選項。-echo選項使與模式進行匹配的字符同時也被髮送給產生這些字符串的當前進程,就好像是當前進程讀取到他們一樣。這在當用戶希望在執行某些指令需要看到回顯的時候非常有用。
  
如果回顯了一個模式,但最終沒有匹配成功,這些字符會被髮送到監視的進程,如果監視的進程再把它們顯示出來的話,那麼用戶將會看到他們兩次。-echo
可能僅僅適合於當用戶不可能不完成模式匹配的情況。例如:下面是摘自於rftp,一個遞歸式ftp腳本,用戶被提示輸入”~g,~p,~l”,以便遞歸的
”獲得,上傳,查看”當前路徑。這些字符和常規的ftp命令相差太遠,用戶除非出錯,否則基本上不會打出”~”後面跟有某些字符的情況。這種情況下,他們
就可能會忽略了正確的結果。
        interact {
                     -echo ~g {getcurdirectory 1}
                     -echo ~l {getcurdirectory 0}
                     -echo ~p {putcurdirectory}
                 }
    -nobuffer選項會把進行模式匹配的字符發送給輸出進程,就像這些字符是被讀取的一樣。這在你想讓進程回顯模式的時候非常有用。例如,下面的代碼監視了哪個用戶在撥叫(一種Hayes模式的Modem),每次都會在腳本的日誌文件中後面看到一個”atd”。
        proc lognumber {} {
                     interact -nobuffer -re "(.*)\r" return
                     puts $log "[exec date]: dialed $interact_out(1,string)"
                 }
                 interact -nobuffer "atd" lognumber
  
在交互過程中,log_user的前一個值被忽略了。特別需要說明的是,interact會強制使他的輸出記錄成日誌(輸出到標準輸出),因爲它認爲用
戶不希望沒有任何迴應的交互。-o選項使下面的key-body模式應用於當前進程的輸出(也就是說用當前進程的輸出來匹配模式)。這對於處理像”在一個
telnet會話中輸入很多錯誤字符(個人認爲:非命令或是選項字符)”的情況非常有用。
  
默認情況下,interact希望用戶對標準輸入進行寫操作,對標準輸出進行讀操作。-u選項通過指定進程名(通常是指定一個spawn_id)來使此
進程的用戶與其他進程進行interact(交互)。這就使兩個毫不相差的進程通過這樣一個聯繫連接起來。爲了協助調試,Expect的調試信息經常會輸
出到標準錯誤輸出(或是是標準輸出,爲了記錄日誌和調試信息)。同樣,解釋器也會交互的從標準輸入讀取字符。例如:下面的代碼,建立了一個登錄進程,它呼
叫用戶,然後使雙方連接在一起。當然其他進程也可以取代這裏的login進程。一個腳本,允許在不提供用戶名與密碼的情況下正常工作。
        spawn login
                 set login $spawn_id
                 spawn tip modem
                 # dial back out to user
                 # connect user to login
                 interact -u $login
  
爲了發送輸出給多個進程,必須使用-output選項指定spawn_id列表。同樣,要給多個進程輸入字符,需要使用-input選項(-input
和-output,還有expect中的-i選項都支持列表,除了特殊變量any_spawn_id在interact命令中無效,在expect中有
效)。
  
所有接下來的選項或字符串(或模式)對當前的輸入有效。直到下一個input選項爲止。如果沒有-input選項,-output選項暗含表示”–
input $user_spawn_id
–output”(在不含有-input選項的模式中也一樣)。如果指定了一個-input選項,那麼它將覆蓋$user_spawn_id,如果出現第
二個–input選項,那麼它將覆蓋$spawn_id,還有可能會指定更多的-input選項。
  
這兩個暗含的輸入進程把它們的輸出默認分別把$spawn_id和$user_spawn_id作爲它們的輸出(做了調換)。如果-input選項後面
沒有-output,那麼這個進程的輸入將會被忽略。-i選項介紹了一種當沒有使用-input或是-output選項時的替代方式。-i選項暗含一個
-o選項。
    使用“間接”spawn_id列可以改變交互進程 (“間接”spawn_id列已經在expect命令裏面講過) 。“間接”spawn_id列可以通過-i,-u,-input或是-output選項指定。
    interpreter  [args]
    使用戶交互的輸入Expect或是Tcl命令,每個命令的結果都會被打印出來。
  
Break和continue會使控制結構(for循環,子函數等等)按照正常的方式運行,但return會使interact把信息返回給它的調用函
數。Inter_return會使它的調用函數返回。例如,如果一個子函數foo調用了inter_return,在執行inter_return時,子
函數foo會返回。其他命令使interpreter繼續提示輸入新的命令。默認情況下,提示包含兩個整數。第一個表示the depth of
evaluation stack嵌套的層數(也就是Tcl_Eval被調用了多少次)。第二個參數是Tcl的history
identifier歷史指針。提示符可以通過定義一個叫做”prompt1”的子函數來設置,這個子函數的輸出會成爲下一個提示符。如果一條語句中包含
半開的(也就是一個,不是一對兒)引號,大括號,中括號或是小括號,那麼下一個提示符會被放在新一行。第二個提示符同樣也可以通過定義一個叫做
”prompt2”的子函數來設置。在interpreter執行過程中,終端使用“精加工”模式,即使它的調用函數使用的是“原始中”模式。如果在沒有
使用-eof選項的情況下,標準輸入被關閉,那麼interpreter就會返回。如果使用了-eof選項,那麼將調用下一個參數。
    log_file [args] [[-a] file]
  
如果指定了文件名,那麼log_file命令會把會話的記錄寫入文件(從執行這條語句開始),如果沒有給定任何參數,那麼log_file命令會停止記
錄。前面的日誌文件都將被關閉。不指定文件名,還可以通過-open或是-leaveopen選項來指定Tcl文件描述符,這和spawn命令的用法一樣
(參見spawn命令)。-a選項強制把log_user命令產生的輸出記錄到日誌。默認情況下,爲了在一次會話中能很方便的多次關閉日誌記
錄,log_file命令會把輸出信息添加到文件尾,而不是覆蓋原來的內容。如果想覆蓋原來的內容,可以使用-noappend選項。-info選項使
log_file命令返回關於最近的non-info(非info選項)參數的描述。
    log_user -info|0|1
    默認時,send/expect對話會被記錄到標準輸出中,可以通過log_user 0來禁止,通過log_user 1來恢復。輸出到日誌文件維持不變。-info選項使log_user命令返回關於最近的non-info(非info選項)參數的描述。
    match_max [-d] [-i spawn_id] [size]
  
這個命令定義Expect內部使用的緩衝區大小。如果沒有參數,返回當前大小。如果使用-d選項的話,將緩衝區設置爲默認大小(初始的默認大小是
2000 Bytes)。如果使用了-i選項,那麼設置的是對應於spawn_id的進程的緩衝區大小。否則設置的是當前進程的。
    overlay [-# spawn_id] [-# spawn_id] [...] program [args]
    終止當前的Expect程序,執行program
args。一個連字符沒有指定參數,那麼連字符將被放到命令之前,就像它是一個登錄Shell一樣。除了那些在命令行中做爲參數指定的spawn_id
外,其他將全部被關閉。這些在命令行中指定的spawn_id將被重定向到指定的文件描述符。這些spawn_id被重定向到文件描述符是爲了新程序來繼
承。例如,下面的命令運行chess程序,而且允許當前程序--chess master(chess控制者)來控制。
        overlay -0 $spawn_id -1 $spawn_id -2 $spawn_id chess
    雖然它犧牲了執行程序化交互的能力,因爲Expect已經失去控制權,但還是要比”interact –u”更有效率。注:在這裏,沒有提供控制終端,因此,如果你斷開或是重定向了標準輸入,那麼控製作業的程序(Shell,login等等)將不能正常訪問。
    parity [-d] [-i spawn_id] [value]
    定義parity是否需要與當前監視的進程的輸出分隔開。如果設爲0,則是分隔開,否則將不分開。如果沒有參數的話,將返回當前值。-d選項將
parity設置爲默認的值(初始默認值爲1,不分開)。-i選項用來指定需要設置parity值的,對應於spawn_id的進程。否則設置當前進程的
parity值。
    remove_nulls [-d] [-i spawn_id] [value]
    此命令用來定義null在匹配模式或是存儲到變量expect_out或是interact_out之前,是否需要與監視進程的輸出分隔開。如果設爲 1,則分開,如果爲0,則不

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章