30分鐘Expect教程入門 並附源碼示例:Linux自動登錄上傳文件並執行ssh

Expect簡介

Expect 是一個可以通過腳本和其它交互程序通信的程序,也可以直接被用於C或C++。

可以實現什麼?

  • 讓計算機自動迴應,比如你可以登錄,無需手動輸入
  • 開始一個遊戲,如果最佳配置沒有出現,一直重啓直到他出現,然後把控制權交給你。
  • 基於預先確定的標準,運行回話,回答問題“是”、“否”,然後把控制權交給你
  • 鏈接到其它站點或者BBS,自動檢索信息發送郵件到本地系統。
  • 傳遞環境變量,當前路徑或者任何類型的信息通過rlogin, telnet, tip, su, chgrp等

安裝

yum  install expect

用法

expect [ -dDinN ] [ -c cmds ] [ -[f|b] ] cmdfile ] [ args ]  

Expect從cmdfile文件讀取一組命令來執行,Expect還可以在支持#!的系統上隱式調用。通過將腳本標記爲可執行文件,並將腳本中的第一行標記爲可執行文件。

#!/usr/local/bin/expect -f
#方式一,如上,放在文件的開頭,其中路徑/usr/local/bin/expect是Expect存在的路徑,文件一般以*.exp結尾。

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

-d標誌啓用一些診斷輸出,主要報告expect和interaction等命令的內部活動。這個標誌與Expect腳本開頭的“exp_internal 1”具有相同的效果,還會打印Expect的版本。(strace命令用於跟蹤語句,trace命令用於跟蹤變量分配)(在使用Expectk時,該選項被指定爲-diag)。

-D標誌啓用交互式調試器。後面應該是整數值。如果值非零,或者按下了^C(或者命中了一個斷點,或者腳本中出現了其他適當的調試器命令),調試器將在執行下一個Tcl過程之前進行控制。有關調試器的更多信息,請參閱README文件或參閱(下面)。(在使用Expectk時,此選項被指定爲-Debug。)

-f標誌前置一個文件,從其中讀取命令。這個標誌本身是可選的,因爲它只在使用#!表示法(參見上面),以便在命令行上提供其他參數。(在使用Expectk時,此選項被指定爲-file。)

默認情況下,命令文件被讀入內存並全部執行。有時需要一次讀取一行文件。例如,以這種方式讀取stdin。爲了強制以這種方式處理任意文件,請使用-b標誌。(在使用Expectk時,此選項被指定爲-buffer。)

如果字符串"-"作爲文件名提供,則讀取標準輸入。(使用”。/-"從一個實際名爲"-"的文件中讀取。)

-i標誌期望交互式地提示命令,而不是從文件中讀取命令。提示通過exit命令或EOF終止。更多信息請參見解釋器(下面)。如果既不使用命令文件也不使用-c,則假定爲-i。(在使用Expectk時,此選項被指定爲-interactive。)

--可用於分隔選項的結束。如果希望向腳本傳遞類似選項的參數,而不讓Expect解釋該參數,那麼這將非常有用。這可以有效地放在#!線,以防止任何標誌的解釋,由期望。例如,下面將保留變量argv中的原始參數(包括腳本名)。

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

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

文件$ exp_library /expect.rc,如果存在rc,則會自動獲取,除非使用-N標誌。(在使用Expectk時,此選項被指定爲-NORC。)緊接其後的是~/.expect文件。rc的來源是自動的,除非使用-n標誌。如果定義了環境變量DOTDIR,則將其視爲一個目錄和.expect。rc從那裏讀取。(在使用Expectk時,此選項被指定爲-norc。)此溯源僅在執行任何-c標誌之後發生。

-v 表示期望打印其版本號並退出。(在使用長標誌名的Expectk中,對應的標誌是-version。)

可選參數args被構造成一個列表並存儲在名爲argv的變量中。argc被初始化爲argv的長度。

argv0被定義爲腳本的名稱(如果不使用腳本,則爲二進制)。例如,下面將打印出腳本的名稱和前三個參數:

send_user "$argv0 [lrange $argv 0 2]\n"

常用命令

Expect使用Tcl(工具命令語言)。Tcl提供了控制流(例如,if、for、break)、表達式求值和其他一些特性,如遞歸、過程定義等。這裏使用但未定義的命令(例如,set, if, exec)是Tcl命令(參見Tcl(3))。Expect支持下面描述的其他命令。除非另外指定,否則命令返回空字符串。

命令按字母順序排列,以便快速定位。然而,新用戶可能會發現,按照順序閱讀衍生、發送、期望和交互的描述會更容易。

注:大寫“E”的“Expect”指的是Expect程序,而小寫“E”的“Expect”指的是Expect程序中的Expect命令

expect [[-opts] pat1 body1] ... [-opts] patn [bodyn]

等待,直到其中一個模式與生成的進程的輸出匹配、經過了指定的時間段或看到文件結束。如果最後的主體是空的,它可以被省略。

如果整個expect語句的參數需要不止一行,那麼所有參數都可以“加固”爲一行,以避免每行都以反斜槓結束。在這種情況下,儘管有括號,通常的Tcl替換仍然會發生。

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

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

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

模式通過三種方式指定。默認情況下,使用Tcl的字符串匹配命令指定模式。(這種模式也類似於C-shell正則表達式,通常稱爲“glob”模式)。gl標誌可以用來保護那些可能與expect標誌匹配的模式。任何以“-”開頭的模式都應該這樣保護。(所有以“-”開頭的字符串都保留爲以後的選項。)
-timeout標誌使當前的expect命令使用以下值作爲超時,而不是使用超時變量的值。

exp_continue命令允許expect本身繼續執行,而不是像通常那樣返回。

interact  將當前進程的控制權交給用戶,以便將擊鍵發送給當前進程,並返回當前進程的stdout和stderr。

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

log_user -info|0|1  默認情況下,send/expect對話被記錄到標準輸出(如果打開,則記錄一個日誌文件)。

overlay [-# spawn_id] [-# spawn_id] [...] program [args]  執行程序參數代替當前的Expect程序,後者將終止。

send  [-flags] string  發送字符串到當前進程

#示例1: 下面的片段尋找一個成功的登錄
expect {
        busy               {puts busy\n ; exp_continue}
        failed             abort
        "invalid password" abort
        timeout            abort
        connected
    }

#示例2:第四個模式必須使用引號,因爲它包含一個空格,否則將把模式與操作分開。具有相同動作的模式(如#第3次和第4次)需要再次列出動作
 expect {
        busy       {puts busy\n ; exp_continue}
        -re "failed|invalid password" abort
        timeout    abort
        connected
    }
#示例3:等待當前進程中的“connected”,或從名爲$proc2的spawn_id中等待“busy”、“failed”或“invalid password”。
 expect {
        -i $proc2 busy {puts busy\n ; exp_continue}
        -re "failed|invalid password" abort
        timeout abort
        connected
    }

exit [-opts] [status]

預期退出或準備退出,

-onexit標誌使下一個參數用作退出處理程序。如果沒有參數,則返回當前退出處理程序

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

 

spawn [args] program [args]

創建一個新的進程運行程序args。它的stdin、stdout和stderr連接到Expect,以便其他Expect命令可以讀寫它們。關閉或進程本身關閉任何文件標識符將斷開連接。

當進程由spawn啓動時,變量spawn_id被設置爲引用該進程的描述符。由spawn_id描述的進程被認爲是當前進程。可以讀取或寫入spawn_id,實際上提供了作業控制。 

wait [args]   

延遲,直到派生的進程(如果沒有命名,則爲當前進程)終止。

wait通常返回一個由四個整數組成的列表。第一個整數是等待的進程的pid。第二個整數是對應的衍生id。第三個整數是-1,如果操作系統出錯,否則爲0。如果第三個整數爲0,則第四個整數是派生的進程返回的狀態。如果第三個整數是-1,那麼第四個整數是操作系統設置的errno值。還設置了全局變量errorCode。

其他元素可能出現在wait的返回值的末尾。第五個可選元素標識一類信息。目前,該元素唯一可能的值是CHILDKILLED,在這種情況下,接下來的兩個值是c樣式的信號名和一個簡短的文本描述.

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

nowait標誌使等待立即返回,表示等待成功。當進程退出(稍後)時,它將自動消失,不需要顯式等待。
還可以使用wait命令使用參數“-i -1”來等待派生進程。與對派生進程的使用不同,該命令可以在任何時候執行。無法控制哪一個過程被收穫。但是,可以檢查返回值的進程id。

 

 

實例

以下爲我寫的publish_TestTo73.exp通過sftp上傳文件,並執行ssh腳本

#!/usr/bin/expect
set TARGET [lindex $argv 0]
set PORT [lindex $argv 1]
set USER [lindex $argv 2]
set PASSWD [lindex $argv 3]
set FILEPATH [lindex $argv 4]
set FILENAME [lindex $argv 5]
set APPNAME [lindex $argv 6]
set SERVER1 [lindex $argv 7]
set timeout 600

#sftp upload jar file
spawn sftp -P 2222 $USER@$TARGET
expect {
        "yes/no" {send "yes\r";exp_continue}
        "*password:" {send "$PASSWD\r";exp_continue}
        "sftp>" {send "put $FILEPATH$FILENAME /$SERVER1/lipp/\r";exp_continue;}
        "*100%*" {send "exit\r"}
}

#expect "100%" 
#send "exit\r"

#ssh run a command
spawn ssh $USER@$TARGET -p $PORT
expect {
    "*yes/no" {send "yes\r"; exp_continue}
    "*password:" {send "$PASSWD\r";exp_continue}
    "*Opt*" {send "$SERVER1\r";exp_continue}
    "*shtermuser*" {send "sudo /data/docker-project/jenkinsStartJar.sh $FILENAME /tmp/lipp/\r"}
}

#interact
expect "*stopped*"
send "exit\r"
expect "Opt> "
send "exit\r"
expect eof

然後新增一個shell內可執行這個expect腳本

expect -f $curpath/publish_TestTo73.exp $ipaddr $port $username $passwd $filepath $filename $appname $SERVER1

參考資料:

expect基礎語法: http://www.tcl.tk/man/expect5.31/expect.1.html#lbAB

TCL命令:http://www.tcl.tk/man/tcl8.5/TclCmd/contents.htm

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