【expect】使用心得
一、expect的安裝
expect是在tcl的基礎上發展起來的,所以在安裝expect之前要先安裝tcl。
(一)tcl安裝
tcl下載地址:
1.下載原始碼包
wget http://nchc.dl.sourceforge.net/sourceforge/tcl/tcl8.4.11-src.tar.gz
2.解壓縮原始碼包
tar xfvz tcl8.4.11-src.tar.gz
3.安裝配置
cd tcl8.4.11/unix
./configure --prefix=/usr/tcl --enable-shared
make
make install
注意:
1、安裝完畢以後,進入tcl原始碼的根目錄,把子目錄unix下面的tclUnixPort.h copy到子目錄generic中。
2、暫時不要刪除tcl原始碼,因為expect的安裝過程還需要用。
(二)安裝expect(需tcl的庫)
1.下載原始碼包
wget http://sourceforge.net/projects/expect/files/Expect/5.45/expect5.45.tar.gz/download
2.解壓縮原始碼包
tar xzvf expect5.45.tar.gz
3.安裝配置
cd expect5.45
. /configure --prefix=/usr/expect --with-tcl=/usr/tcl/lib --with-tclinclude=../tcl8.4.11/generic
make
make install
ln -s /usr/tcl/bin/expect /usr/expect/bin/expect
二、expect的簡要說明
我們通過Shell可以實現簡單的控制流功能,如:迴圈、判斷等。但是對於需要互動的場合則必須通過人工來干預,有時候我們可能會需要實現和互動程式如telnet伺服器等進行互動的功能。而Expect就使用來實現這種功能的工具。
三、expect的簡單用法
(一)expect基礎概念
1. [#!/usr/bin/expect]
這一行告訴作業系統腳本里的程式碼使用那一個shell來執行。這裡的expect其實和linux下的bash、windows下的cmd是一類東西。 這一行需要在指令碼的第一行。
2. [set timeout 30]
設定超時時間,計時單位為:秒 ,timeout -1 為永不超時
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執行程序加個殼,用來傳遞互動指令。
4. [expect "password:"]
這裡的expect也是expect的一個內部命令,expect的shell命令和內部命令是一樣的,但不是一個功能,習慣就好了。這個命令的意思是判斷上次輸出結果裡是否包含“password:”的字串,如果有則立即返回,否則就等待一段時間後返回,這裡等待時長就是前面設定的timeout
5. [send "ispass\r"]
這裡就是執行互動動作,與手工輸入密碼的動作等效。
溫馨提示: 命令字串結尾別忘記加上“\r”,如果出現異常等待的狀態可以核查一下。
6. [interact]
執行完成後保持互動狀態,把控制權交給控制檯,這個時候就可以手工操作了。如果沒有這一句登入完成後會退出,而不是留在遠端終端上。如果你只是登入過去執行
7.$argv 引數陣列
expect指令碼可以接受從bash傳遞過來的引數.可以使用[lindex $argv n]獲得,n從0開始,分別表示第一個,第二個,第三個….引數
(二)expect簡單用法
#!/usr/bin/expect -f
set timeout 60 #設定超時時間
log_file test.log #設定指令碼日誌
log_user 1 #是否顯示指令碼輸出資訊 1代表顯示,0代表不顯示
set hostname [lindex argv 0] #接收第一個引數
set password [lindex argv 1]
spawn ssh root@$hostname #連線遠端機器
expect {
"(yes/no)"
{
send "yes\r"
expect "*password:" {send "$password\r"}
}
"*password"
{
send "$password\r"
}
}
send "echo ==\$(rpm -qa | grep mariadb)==\r"
expect -re "==.*==.*==(.*)=="
set mariadb $expect_out(1,string)
expect "*]#"
send "rpm -e --nodeps $mariadb\r"
expect "*]#"
send "exit\r"
expect eof
上述程式碼即為一個簡單的expect指令碼,登入到遠端機器並解除安裝mariadb,expect中最常用的就是”expect”和“send”命令。
expect “pattern”
send “command\r”
當遠端機出現了匹配”pattern”的字串,就執行”command”命令,在執行完命令之後別忘了加上回車符,如此便可實現自動輸入密碼等一系列功能。
四、shell巢狀expect
#!/bin/bash
hostname=$1 #接收第一個引數
password=$2
/usr/bin/expect <<-EOF # 重定向到expect
spawn ssh root@${hostname}
expect {
"(yes/no)"
{
send "yes\r"
expect "*assword:" {send "$password\r"}
}
"*assword"
{
send "$password\r"
}
}
expect "*]#"
send "echo 'export MAVEN_HOME=/usr/local/maven' >> /etc/profile\r"
send "echo 'export M2_HOME=\\\$MAVEN_HOME' >> /etc/profile\r"
send "echo 'export PATH=\\\$PATH:\\\$MAVEN_HOME/bin' >> /etc/profile\r"
expect "*]#"
send "source /etc/profile\r"
expect "*]#"
send "exit\r"
expect eof
EOF #結束重定向
五、expect常見問題
1、expect指令碼中source命令不起作用?
shell指令碼中巢狀expect指令碼,再編寫source命令即可正常使用
2、shell巢狀expect指令碼中$expect_out(1,string)無法獲得匹配字串?
單純使用expect指令碼即可正常獲取
3、shell巢狀expect指令碼中對字元轉義需要三個反斜槓,expect指令碼中對字元轉義只需要一個反斜槓。