在編寫腳本時,可能會遇到須要在另外一臺主機上執行一個命令,或者在本機拷貝另外一臺主機內的一個文件。若是兩臺主機之間沒有作互信,就會牽扯到用戶輸入密碼的交互過程,這對編寫自動腳原本說, 就行不通了。python
要實如今腳本內的自動交互,就須要 expect正則表達式
expect 是一個用來處理交互的命令。藉助 expect 能夠將交互過程寫在一個腳本里,就能夠實現自動化完成。上面的問題也能獲得解決。shell
形象來講,以下命令的交互都能獲得解決:bash
CentOS / RHEL 安裝 expect 服務器
# yum install expect -y
expect 中最關鍵的四個命令: send 、 expect 、spawn 、 interact
ssh
(1) send 命令測試
send命令接收一個字符串參數,並將該參數發送到進程。spa
[root@localhost ~]# expect expect1.1> send "hello china\n" hello china
(2) expect命令blog
A. 基礎知識進程
expect命令和send命令正好相反,expect一般是用來等待一個進程的反饋。expect能夠接收一個字符串參數,也能夠接收正則表達式參數。和上文中的send命令結合。
#!/usr/bin/expect expect "hi\n" send "hello there!\n"
上面腳本的意思:
expect "hi\n" --> 從標準輸入中等待 "hi\n"
send "hello there!\n" --> 向標準輸出輸出 hello where
若是寫成簡單的僞代碼以下:
if [ "$cmd" == "hi" ] ; then echo "hello there!" fi
來看一個簡單的 expect 腳本:
#!/usr/bin/expect expect "hi\n" send "you typed <$expect_out(buffer)>" send "but I only expected <$expect_out(0,string)>"
執行結果:
經過執行腳本,能夠斷定:
$expect_out(buffer) 匹配到的是全部輸入
$expect_out(0,string) 匹配到 expect 參數的輸入
B. 模式 - 動做
(a)單一分支模式語法:
expect "hi" {send "You said hi\n"}
只有當輸入 hi 時, 纔會返回 "You said hi\n"
(b)多分支模式語法:
expect "hi" { send "You said hi\n" } \ "hello" { send "Hello yourself\n" } \ "bye" { send "That was unexpected\n" }
匹配到 hi 、hello 、 bye 執行相應的輸出:
hi --> You said hi\n hello --> You said hi\n bye --> That was unexpected\n
(3) spawn 命令
上面的測試都是經過手動輸入來進行交互的,spawn 命令就是用來啓動新的進程,而後經過 send 和 expect 和 spawn 打開的進程進行交互的。
#!/usr/bin/expect set timeout -1 spawn scp root@192.168.118.15:/root/testfile /root/ expect "*password*" send "123456\r" expect "100%" expect eof
執行結果:
經過 spawn 配合 expect 、send 就能實現自動交互了,接下來分析下這個代碼:
(4)interact 命令
經過上面三個命令 spawn 、 send 、 expect 已經能完成不少自動化腳本了,可是,若是須要在適當的時候,須要人工干預這個過程,就須要用到 interact 命令。
#!/usr/bin/expect set timeout -1 spawn ssh root@192.168.118.15 expect "*password*" send "123456\r" expect "#*" send "ip a | egrep global\r" interact
expect 常常是做爲腳本出來的, 接下來經過我平常使用的幾個實例來講明:
scp 執行流程如圖:
在編寫實現 scp 以前,咱們要考慮:
(1)若是是第一次執行 scp 須要確認服務器公鑰,若是不是第一次執行則無需這一步
(2)timeout 時間設定,當拷貝大文件時,timeout設置的太短會形成文件沒有徹底的傳輸完成。
在編寫腳本的時,須要考慮以上問題,腳本以下:
#!/usr/bin/expect set timeout 3 set host "192.168.118.15" set username "root" set password "123456" # 使用spawn 啓動一個新進程執行 scp 命令 spawn scp $username@$host:/root/testfile /root/ # 在這裏timeout 爲 3秒,超過三秒執行下一個匹配 expect "*yes/no*" {send "yes\r"} expect "*password*" {send "$password\r"} # 在scp傳輸文件時,timeout時間設置爲無限時,當大文件傳輸時,須要更多的時間 set timeout -1 # 當匹配到 傳輸完成 100%後,轉到下一步 expect "100%" # 使用 eof 結束該進程,由於上面設置 timeout 爲 -1 無限時 expect eof
執行結果:
能夠看到,文件傳輸須要 14 秒,而上面若是設置的超時時間低於 14 秒, 則文件傳輸不完整。
在平常使用中,expect 結合 shell 使用,在 shell 中引用 expect 腳本以下:
#!/usr/bin/bash ... [shell 執行腳本] ... expect <<EOF set timeout 3 ... [expect 執行腳本] ... EOF ... [shell 執行腳本] ...
例如:拷貝一個壓縮包到本地,而後解壓
#!/bin/bash host="192.168.118.15" username="root" password="123456" expect <<EOF set timeout 3 spawn scp $username@$host:/root/testfile.tar.gz /root/ expect "*yes/no*" {send "yes\r"} expect "*password*" {send "$password\r"} set timeout -1 expect "100%" expect eof EOF echo '開始解壓...' tar xf testfile.tar.gz if [ $? -eq 0 ]; then echo '解壓完成.' fi
執行結果:
ssh遠程執行命令流程以下:
執行腳本:
#!/usr/bin/expect set timeout 3 set host "192.168.118.15" set username "root" set password "123456" spawn ssh $username@$host ifconfig expect "*yes/no*" {send "yes\r"} expect "*password*" {send "$password\r"} expect eof
執行結果:
expect 匹配 shell 使用仍是很強大的,尤爲是在沒有 python 和沒法鏈接互聯網的環境中。