文章目錄
一、概述
expect是Unix系統中用來進行自動化控制和測試的軟體工具,由Don Libes製作,作為Tcl指令碼語言的一個擴充,應用在互動式軟體中如telnet,ftp,Passwd,fsck,rlogin,tip,ssh等等。該工具利用Unix偽終端封裝其子進程,允許任意程式通過終端接入進行自動化控制;也可利用Tk工具,將互動程式封裝在X11的圖形化使用者介面中。
我們通過Shell可以實現簡單的控制流程功能,如:迴圈、判斷等。但是對於需要互動的場合則必須通過人工來幹預,比如普通使用者使用sudo命令時就需要我們手動輸入密碼;expect就是能夠完成這種自動互動任務,而無需人的幹預。Expect的作者Don Libes在1990年開始編寫Expect時對Expect做有如下定義:Expect是一個用來實現自動互動功能的軟體套件(Expect [is a] software suite for automating interactive tools)。系統管理員可以使用它建立用來實現對命令或程式提供輸入的指令碼:一般來說這些輸入都需要手工輸入(比如之前提到的執行sudo程式期望使用者從終端輸入使用者密碼)進行的,Expect則可以根據程式的提示 類比標準輸入給程式提供資訊來實現互動程式執行。甚至可以實現簡單的BBS聊天機器人。
Expect是不斷髮展的,隨著時間的流逝,其功能越來越強大,已經成為系統管理員的的一個強大助手。Expect需要Tcl程式設計語言的支援,要在系統上運行Expect必須首先安裝Tcl。
二、工作原理從最簡單的層次來說,Expect的工作方式象一個通用化的Chat指令碼工具。Chat指令碼最早用於UUCP網路內,以用來實現電腦之間需要建立串連時進行特定的登入工作階段的自動化。
Chat指令碼由一系列
expect-send對組成:expect
等待輸出中輸出
特定的字元,通常是一個提示符,如果等到了就使用send
發送特定的
響應,例如下面我們使用expect-send對來類比一遍使用者名稱和密碼的互動式輸入# expect
等待標準輸出中出現"
Login:"字串,如果等到了"
Login:"字串,就使用send回應
somebody(其中\n用於類比敲斷行符號)
expect "Login:"
send "somebody
\n"
# expect等待"Password:",使用send回應111111
expect "Password:"
send "111111\n"上述幾條語句描述出了Expect最簡單的指令碼操作模式。三、應用3.1自動登陸ssh伺服器
使用expect實現自動登入的指令碼,網上有很多,可是都沒有一個明白的說明,初學者一般都是照抄、收藏。可是為什麼要這麼寫卻不知其然。本文用一個最短的例子說明指令碼的原理。
#!/usr/bin/expect
set timeout 30
spawn ssh test@127.0.0.1
expect "password:"
send "123456\n"
interact1. [#!/usr/bin/expect] 這一行告訴作業系統指令碼裡的代碼使用那一個shell來執行。這裡的expect其實和linux下的bash、windows下的cmd是一類東西。 注意:這一行需要在指令碼的第一行。2. [set timeout 30] 設定逾時時間,單位是秒;expect逾時等待的時間。預設timeout為10s。 3. [spawn ssh test@127.0.0.1] spawn是進入expect環境後才可以執行的expect內部命令,如果沒有裝expect或者直接在shell下執行是找不到spawn命令的。這個就好比cd是shell的內建命令,離開shell,就無法執行cd一樣。 它主要的功能是給ssh運行進程加個殼,用來傳遞互動指令。 4. [expect "password:"] 這裡的expect也是Expect指令碼語言的一個內部命令。在shell下輸入expect,會進入expect的工作介面,這個expect是一個shell命令,而[expect "password:"] 中的expect只是一個跟expect指令碼名同名的一個內建命令。這個命令的意思是判斷上次輸出結果裡是否包含“password:”的字串,如果有則立即返回,向下執行;否則就一直等待,直到逾時時間到,就是2裡的30秒。5. [send "123456\n"] 這裡就是執行互動動作,與手工輸入密碼的動作等效。效果上跟使用者手動在終端上輸入123456之後敲一個斷行符號一樣。6. [interact] 執行完成上述命令後保持在互動狀態,此時Expect會把控制權交給控制台,這個時候就變回手工操作,Expect已經執行完成。如果沒有這一句登入完成後會立刻退出,而不是留在遠程終端上。如果你只是登入過去執行一段命令就退出,可將其改為[expect eof]該指令碼執行現象如下:gyl@gyl:~$ ./
test.exp
spawn ssh
test@127.0.0.1
test@127.0.0.1's password:
Linux gyl 2.6.32-46-generic #108-Ubuntu SMP Thu Apr 11 15:55:01 UTC 2013 i686 GNU/Linux
Ubuntu 10.04.4 LTS
Welcome to Ubuntu!
* Documentation: https://help.ubuntu.com/
New release 'precise' available.
Run 'do-release-upgrade' to upgrade to it.
Last login: Sat May 11 01:08:19 2013 from localhost
$ 3.2封裝scp語句實現上傳下載的自動互動#!/usr/bin/expect
#
#auto down/up files from/to server over scp.protocol
#Usage:
# autoscp -down srcpath (the same as autoscp -down srcpath .)
# autoscp -down srcpath dstpath (dstpath is based on $pwd)
# autoscp -up srcpath (the same as autoscp -up srcpath ~)
# autoscp -up srcpath dstpath (dstpath is based on ~ on the server)
#
set timeout 100
set cmd [lindex $argv0]
set option [lindex $argv 0]
set srcpath [lindex $argv 1]
set dstpath [lindex $argv 2]
#parse command number
switch -- $argc {
2 {
set dstpath .
}
3 {
}
default {
send_user "Usage:$cmd option srcpath \[dstpath\]\n"
exit
}
}
#parse command and do it.
if {$option=="-down"} {
spawn scp -r gyl@127.0.0.1:/home/gyl/$srcpath $dstpath
} else {
if {$option=="-up"} {
spawn scp -r $srcpath gyl@127.0.0.1:/home/gyl/$dstpath
} else {
send_user "bad arg:\"$option\"\n"
exit
}
}
#autofill infomation
expect "password:"
send "123456\n"
#exit
expect eof該指令碼仿照C語言的命令列參數,用到switch-case語句,if-else語句,功能算是比較全面了。該指令碼規定了有4種使用方法,不符合使用要求時給出相應提示。其中上傳和下載每種操作含有加dstpath和不含dstpath,共4種;autoscp -down srcpath dstpath #srcpath基於伺服器使用者主目錄,dstpath基於本地目前的目錄
autoscp -down srcpath #等價於autoscp -down srcpath .
autoscp -up srcpath dstpath #srcpath基於本地目前的目錄,dstpath基於伺服器使用者主目錄
autoscp -up srcpath #等價於autoscp -up srcpath ~NOTE:因為該指令碼使用scp的上傳下載功能,當操作打檔案時,耗時較久,如果timeout值過小,逾時時間一到,資料轉送就會終止,程式退出。因此timeout值應該根據檔案大小做適當調整。四、參考資料Expect 手冊 中文版Linux 自動登入系統 執行命令<2> expectShell_scp expect實現linux shell + expect:批量scp指令碼工具
來自為知筆記(Wiz)Time=2013-04-27 17:24:26