expect介紹
expect
是一個自動交互功能的工具。expect
命令會新建一個子進程,通過spawn
來執行shell
腳本,監測腳本的返回結果,然後通過expect
判斷要進行的交互輸入內容。
藉助Expect
處理交互的命令,可以將交互 過程如:ssh
登錄,ftp
登錄等寫在一個腳本上,使之自動化完成.尤其適用於需 要對多臺服務器執行相同操作的環境中,可以大大提高系統管理人員的工作效率 。
expect
安裝
Expect
是一個基於TCL
開發出的語言包。系統一般不會自帶,需要自行安裝。
TCL(Tool Command Language)工具腳本語言,是Linux內的一種語言包。
系統爲RHEL/CentOS
:
yum install expect
系統爲Debian/Ubuntu
:
apt-get install expect
expect
腳本
expect
腳本以#!/usr/bin/expect
開頭,用來告訴操作系統腳本里的代碼使用那一個shell
來執行。這裏的expect
和linux
下的bash
、windows
下的cmd
是一類東西。
以.exp或者.ex結束,通過./xxx.exp
運行(需要可執行權限),類似bash
腳本。
也可以以
sh
結尾,通過expect ./xx.sh
執行,如expect ./auto_deploy.sh
。
expect
命令選項
expect [選項] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
選項
-
-v
:顯示expect
版本信息。 -
-f
:從文件讀取命令,僅用於使用#!
時。如果文件名爲file
,則從stdin
讀取(使用./file
從文件名爲file
的文件讀取)。 -
-c
:從命令行執行expect
腳本,默認expect
是交互地執行的,如下所示:expect -c 'expect "\n" {send "pressed enter\n"}
如果你執行了上面的腳本,它會等待輸入換行符
\n
。按enter
鍵以後,它會打印出pressed enter
這個消息,然後退出。 -
-i
:使用-i
選項,可以通過來自於標準輸入的讀命令來交互地執行expect
腳本。如下所示:expect -i arg1 arg2 arg3 expect1.1>set argv arg1 arg2 arg3 expect1.2>
正常情況下,當你執行上面的
expect
命令的時候(沒有-i
選項),它會把arg1
當成腳本的文件名,所以-i
選項可以讓腳本把多個參數當成一個連續的列表。 -
-d
:可以輸出輸出調試信息$ cat sample.exp # !/usr/bin/expect -f expect “\n”; send “pressed enter”; $ expect -d sample.exp expect version 5.43.0 argv[0] = expect argv[1] = -d argv[2] = sample.exp set argc 0 set argv0 “sample.exp” set argv “” executing commands from command file sample.exp expect: does “” (spawn_id exp0) match glob pattern “\n”? no expect: does “\n” (spawn_id exp0) match glob pattern “\n”? yes expect: set expect_out(0,string) “\n” expect: set expect_out(spawn_id) “exp0” expect: set expect_out(buffer) “\n” send: sending “pressed enter” to { exp0 pressed enter}
-
-b
: 通常,expect
會在執行腳本之前,把整個腳本都讀入到內存中。-b
選項可以讓expect
一次只讀取腳本中的一行。當你沒有寫完整個腳本的時候,這是十分有用的,expect
可以開始執行這個不完整的腳本。expect -b
-
-d
:讓expect
不解釋命令行參數你可以使用標識符讓
expect
不解釋命令行參數。你可以像下面這樣的讀入命令行參數:$ cat print_cmdline_args.exp #!/usr/bin/expect puts ‘argv0 : [lindex $argv 0]’; puts ‘argv1 : [lindex $argv 1]’;
當執行上面的腳本的時候,會跳過命令行選項,它們會被當成參數(而不是
expect
選項),如下所示:$ expect print_cmdline_args.exp -d -c argv0 : -d argv1 : -c
expect
內置命令
-
set timeout
: 設置超時時間的,單位是:秒 。例如:set timeout 30
# 永遠等待,不會超時 set timeout -1
-
spawn
:spawn
是進入expect
環境後纔可以執行的expect
內部命令,如果沒有裝expect
或者直接在默認的SHELL
下執行是找不到spawn
命令的。所以不要用which spawn
之類的命令去找spawn
命令。spawn
用來啓動新的進程的,spawn
後的send
和expect
命令都是和spawn
打開的進程進行交互的。# 直接運行一個 bash 腳本 spawn /mnt/sh_expect.sh # 直接運行一個 bash 命令 spawn ssh -p ${port} $user@$host
-
send
:用於向進程發送命令字符串 ,這裏就是執行交互動作,與手工輸入的動作等效。 命令字符串結尾別忘記加上\n
。 -
expect
:expect
也是expect
的一個內部命令,expect
的shell
命令和內部命令是一樣的,但不是一個功能。這個命令的意思是判斷上次輸出結果裏是否包含指定的字符串,如果有則立即返回,否則就等待一段時間後返回,這裏等待時長就是set timeout xxx
設置的時間。# 從標準輸入中等到hi和換行鍵後,向標準輸出輸出hello there expect "hi\n" send "hello there!\n" # 退出 spawn 會話,返回當前的shell進程 send "exit\n" # 退出expect expect eof
-
interact
:從自動交互狀態退出到輸入狀態,由用戶完成剩餘的操作.,這個時候就可以手工操作了。如果沒有這一句登錄完成後會退出,而不是留在遠程終端上。 -
exp_continue
:重置set timeout
設置的時間,重新執行當前expect
分支# 如果匹配到*assword,那麼發送密碼,並進入下面的expect語句(uname -a語句)。 # 如果匹配到yes/no,那麼發送yes,並重新執行這個expect分支語句。 expect { "*assword" {send "123456\r";} "yes/no" {send "yes\r";exp_continue} }
命令行參數
$argc,$argv 0,$argv 1 ... $argv n
argc
表示命令行參數個數,後面分別表示各個參數項,0表示第一個參數,1表示第二個參數,以此類推,可以通過lindex
獲取對應參數值[lrange $argv 0 0]
。
if {$argc < 2} {
puts stdout "$argv0 err params\n"
exit 1
}
set user [lindex $argv 0]
set password [lindex $argv 1]
參數存在argv
當中,[lrange $argv 0 0]
表示第1
個參數,[lrange $argv 0 4]
爲第一個到第五個參數。如果需要計算的話必須用expr
,如計算2-1
,則必須用[expr 2-1]
;
語法
expect
遵循tcl
的語法規範,基礎語法部分可以查看這裏,循環、條件判斷、各種運算符都有詳細的說明