一 expect介紹
expect
是一個免費的編程工具,用來實現自動的交互式任務,而無需人為干預。說白了,expect
就是一套用來實現自動交互功能的軟件。需要安裝
yum install -y expect
expect基礎
在使用expect
時,基本上都是和以下四個命令打交道:
命令 作用
spawn 啟動新的進程
expect 從進程接收字符串
send 用於向進程發送字符串
interact 允許用戶交互
spawn
命令用來啟動新的進程,spawn
后的expect
和send
命令都是和使用spawn
啟動的新進程進行交互。expect
通常用來等待一個進程的反饋,我們根據進程的反饋,再使用send
命令發送對應的交互命令。send
命令接收一個字符串參數,並將該參數發送到進程。interact
命令用的其實不是很多,一般情況下使用spawn
、expect
和send
和命令就可以很好的完成我們的任務;但在一些特殊場合下還是需要使用interact
命令的,interact
命令主要用於退出自動化,進入人工交互。比如我們使用spawn
、send
和expect
命令完成了ftp登陸主機,執行下載文件任務,但是我們希望在文件下載結束以后,仍然可以停留在ftp命令行狀態,以便手動的執行后續命令,此時使用interact
命令就可以很好的完成這個任務。
總結expect自動應答的基本步驟
第一步: 運行一個程序或命令=> spawn 命令信息
第二步: 識別產生信息關鍵字=> expect 捕獲關鍵字 {send 應答信息}
第三步: 根據識別關鍵做處理=> send 應答信息
二 expect實例
自動應答腳本
#!/usr/bin/expect
spawn ssh root@192.168.12.20 uptime
expect "yes/no"
send "yes\n"
expect "*assword"
send "1\n"
expect eof
解釋
#1、#!/usr/bin/expect -f:使用expect來解釋該腳本
#2、spwan:
spawn是進入expect環境后才可以執行的expect內部命令,如果沒有裝expect或者直接在默認的SHELL下執行是找不到spawn命令的。它主要的功能是給ssh運行進程加個殼,用來傳遞交互指令;
#3、expect:
expect "*assword":這里的expect也是expect的一個內部命令,這個命令的意思是判斷上次輸出結果里是否包含“password”的字符串,如果有則立即返回;否則就等待一段時間后返回,這里等待時長就是前面設置的30秒;
#4、send:
send "1\n":當匹配到對應的輸出結果時,就發送密碼到打開的ssh進程,執行交互動作;
首次登陸之后,再次登陸,就不會出現yes/no的提示了,所以上述腳本再次運行會出現spawn 命令出現交互式提問的expect 匹配不上的情況,此時腳本會阻塞在原地,我們可以set timeout 3設置超時時間,單位為秒,默認情況下是10秒,以保障腳本超時則結束,
#!/usr/bin/expect -f
spawn ssh root@192.168.12.20 uptime
set timeout 3 # 某一條expect語句在原地匹配,超過了3秒,無論是否匹配成功都會繼續執行下一條指令
expect "yes/no"
send "yes\n"
expect "*assword"
send "1\n"
expect eof
設置超時時間的目的僅僅只是為了讓腳本不要一直卡在原地,要真正解決上述問題,需要改寫成下述形式
#!/usr/bin/expect -f
spawn ssh root@192.168.12.20 hostname
# 注意
# 1、{}一定要換行
# 2、下述語句就一個expect,代表匹配了一次,會匹配完一行就匹配下一行
expect {
"yes/no" {send "yes\r";exp_continue}
"*assword" {send "1\n"}
}
expect eof
練習
[root@aliyun ~]# cat 1.sh
#!/usr/bin/expect -f
spawn ssh egon@127.0.0.1
set timeout -1 # 設置為-1代表永不超時,如果expect沒有捕捉到就一直停在原地
expect {
"yes/no" {send "yes\n"}
}
expect {
"password" {send "1\n"}
}
expect "*egon*"
send "ls\n"
expect "\$"
send "pwd\n"
expect "\$"
send "exit\n" # 注意一定要輸入exit結束信號
expect eof # 最后關閉匹配
[root@aliyun ~]#
interact交互
interact
:執行完成后保持交互狀態,把控制權交給控制台,這個時候就可以手工操作了。如果沒有這一句登錄完成后會退出,而不是留在遠程終端上。
[root@egon ~]# cat test.sh
#!/usr/bin/expect -f
spawn ssh root@192.168.12.20
expect {
"yes/no" {send "yes\r";exp_continue}
"*assword" {send "1\n"}
}
interact
[root@egon ~]#
[root@egon ~]# ./test.sh
spawn ssh root@192.168.12.20
root@192.168.12.20's password:
Last login: Wed Aug 26 21:28:04 2020 from egon
+--------------------------------------------+
| |
| 你當前登錄的是支付業務后台數據庫服務 |
| 請不要刪庫 |
| |
+--------------------------------------------+
[root@egon ~]# pwd
/root
[root@egon ~]# echo "hello"
hello
[root@egon ~]# exit
登出
Connection to 192.168.12.20 closed.
[root@egon ~]#
三 為expect腳本傳參
shell腳本中的變量無法直接在expect中使用的,若expect需要使用變量
一方面可以自己定義
#!/usr/bin/expect -f
set timeout -1
set user "root"
set ip "192.168.12.20"
set cmd "hostname"
set pass "1"
spawn ssh $user@$ip $cmd
expect {
"yes/no" {send "yes\r";exp_continue}
"*assword" {send "$pass\n"}
}
expect eof
另外一方面可以通過下述方式引入shell變量,注意此時解釋器換成#!/bin/bash
#!/bin/bash
user="root"
ip="192.168.12.20"
cmd="hostname"
pass="1"
expect << EOF
spawn ssh $user@$ip $cmd
expect {
"yes/no" {send "yes\r";exp_continue}
"*assword" {send "$pass\n"}
}
expect eof
EOF
此外,expect腳本還可以從命令行獲取參數
在expect中,$argc
表示參數個數,而參數值存放在$argv
中,比如取第一個參數就是[lindex $argv 0]
,以此類推。
[root@egon ~]# cat test.sh
#!/usr/bin/expect -f
if {$argc != 4} {
puts "Usage:./script.sh <ip> <username> <password> <cmd>"
exit 1
}
set ip [lindex $argv 0]
set user [lindex $argv 1]
set pass [lindex $argv 2]
set cmd [lindex $argv 3]
set timeout -1
spawn ssh $user@$ip $cmd
expect {
"yes/no" {send "yes\r";exp_continue}
"*assword" {send "$pass\n"}
}
expect eof
[root@egon ~]# ./test.sh
Usage:./script.sh <ip> <username> <password> <cmd>
[root@egon ~]# ./test.sh 192.168.12.20 root 1 hostname
spawn ssh root@192.168.12.20 hostname
root@192.168.12.20's password:
egon
能夠在工作中熟練的使用Shell腳本就可以很大程度的提高工作效率,如果再搭配上expect,那么很多工作都可以自動化進行,對工作的展開如虎添翼。如果你會Python的話,你的視野將會更加開闊,那個時候你又會“嫌棄”expect了。