expect是建立在tcl基礎上的一個工具,它用來讓一些需要互動的任務自動化地完成。
因為expect是基于tcl的,是以需要你的系統中安裝有tcl
如何檢查?
[root@dev ~]# whereis tcl
tcl: /usr/lib/tcl8.4 /usr/share/tcl8.4
如果看不到結果,請先安裝tcl
> 安裝tcl
解壓tcl安裝包後
cd tcl8.4.11/unix/
./configure --prefix=/usr/local/tcl/ --enable-shared
make && make install
> 安裝expect
解壓expect安裝包後
cd expect-5.43
./configure --prefix=/usr/local/expect/ --with-tcl=/usr/local/tcl/lib/ --with-tclinclude=/opt/tcl8.4.11/generic/ --enable-shared
注意:指定的/opt/tcl8.4.11/generic/ 為我們上面解壓的tcl目錄
> 建立連接配接符号
ln -s /usr/local/expect/bin/expect /usr/bin/expect
> 檢視連接配接符号
ls -l /usr/bin/expect
lrwxrwxrwx. 1 root root 28 9月 8 11:21 /usr/bin/expect -> /usr/local/expect/bin/expect
這個符号連結将在編寫expect腳本檔案時用到,例如在expect檔案頭部會指定用于執行該腳本的shell
#!/usr/bin/expect
> 測試
[root@localhost opt]# expect
expect1.1> exit
[root@localhost opt]#
這樣就可以開始運作expect腳本了。
1. [#!/usr/bin/expect]
這一行告訴作業系統腳本裡的代碼使用那一個shell來執行。這裡的expect其實和linux下的bash、windows下的cmd是一類東西。
注意:這一行需要在腳本的第一行。
2. [set timeout 30]
基本上認識英文的都知道這是設定逾時時間的,現在你隻要記住他的計時機關是:秒。timeout -1 為永不逾時,預設情況下,timeout是10秒;
3. [spawn ssh -l username 192.168.1.1]
spawn是進入expect環境後才可以執行的expect内部指令,如果沒有裝expect或者直接在預設的shell下執行是找不到spawn指令的。是以不要用 “which spawn“之類的指令去找spawn指令。好比windows裡的dir就是一個内部指令,這個指令由shell自帶,你無法找到一個dir.com 或 dir.exe 的可執行檔案。
它主要的功能是給ssh運作程序加個殼,用來傳遞互動指令。
spawn後面加上需要執行的shell指令,比如說spawn sudo touch testfile
4. [expect "password:"]
這裡的expect也是expect的一個内部指令,有點暈吧,expect的shell指令和内部指令是一樣的,但不是一個功能,習慣就好了。這個指令的意思是判斷上次輸出結果裡是否包含“password:”的字元串,如果有則立即傳回,否則就等待一段時間後傳回,這裡等待時長就是前面設定的30秒
5. [send "ispass\r"]
這裡就是執行互動動作,與手工輸入密碼的動作等效。
溫馨提示: 指令字元串結尾别忘記加上“\r”,如果出現異常等待的狀态可以核查一下。
6. [interact]
執行完成後保持互動狀态,把控制權交給控制台,這個時候就可以手工操作了。如果沒有這一句登入完成後會退出,而不是留在遠端終端上。如果你隻是登入過去執行
7. $argv 參數數組
expect腳本可以接受從bash傳遞過來的參數.可以使用[lindex $argv n]獲得,n從0開始,分别表示第一個,第二個,第三個....參數
其中,$argc為指令行參數的個數,$argv0為腳本名字本身,$argv為指令行參數。[lrange $argv 0 0]表示第1個參數,[lrange $argv 0 4]為第一個到第五個參數。與c語言不一樣的地方在于,$argv不包含腳本名字本身。
8. send和send_user
send會将expect腳本中需要的資訊發送給spawn啟動的那個程序,而send_user隻是回顯使用者發出的資訊,類似于shell中的echo而已。
9. 如果你在第一行(#!那行)使用-d (debug參數),可以在運作的時候輸出一些很有用的資訊
比如你會看見
argv[0] = /usr/bin/expect argv[1] = -d argv[2] = ./launch.exp argv[3] = 1 argv[4] = 2 argv[5] = 3
使用這些也可以完成參數傳遞
10. exp_continue的用法
expect {
-re "permission denied, please try again." {
send_user "error:permission denied.\n"
exit
}
-re "are you sure you want to continue connecting (yes/no)?" {
send "yes\r";exp_continue
-re "assword:" {
send "$loginpass\r";exp_continue
-re "connection refused" {
timeout {
eof {
}
使用exp_continue後,會重新從目前expect塊的開始重新執行,可以簡單了解問while循環的continue
下面的腳本例子,實作了:登入一個linux伺服器,執行 df -h 等指令
vi expectexample.sh 後輸入下面的腳本内容儲存後,使用chmod +x expectexample.sh 指令為腳本賦予可執行權限。
#!/usr/bin/expect -f
#-------------------------------------------- set the variable,you can modify the value
set ipaddr [lrange $argv 0 0]
set port [lrange $argv 1 1]
set loginuser [lrange $argv 2 2]
set loginpass [lrange $argv 3 3]
set cmd_prompt "]#|~]?"
# 逾時時間,機關(秒)
set timeout 3600
#-------------------------------------------- login by ssh
spawn ssh -p $port $loginuser@$ipaddr
-re "connection refused" {
send_user "error:connection refused.\n"
send "yes\r"
exp_continue
send "$loginpass\r"
-re $cmd_prompt {
send "\r"
#-------------------------------------------- now,we do some commands
send "df -h\r"
send "free -m\r"
send "uptime\r"
send "cd /opt\r"
send "mkdir shanhy123\r"
send "cd shanhy123\r"
send "echo 123 > 123.txt\r"
send "/opt/xs.sh\r"
send "exit\r"
expect eof
#interact
-------------------------------------------------
其中 xs.sh 為我寫的一個測試的 shell 腳本,裡面故意做了一個sleep 模拟耗時操作,代碼如下:
#!/bin/bash
sleep 10
echo abc > /opt/abc.txt
注意:expect腳本必須以interact或expect eof結束,執行自動化任務通常expect eof就夠了。