expect 實現自動交互腳本

1. 說明

  在編寫腳本時,可能會遇到須要在另外一臺主機上執行一個命令,或者在本機拷貝另外一臺主機內的一個文件。若是兩臺主機之間沒有作互信,就會牽扯到用戶輸入密碼的交互過程,這對編寫自動腳原本說, 就行不通了。python

要實如今腳本內的自動交互,就須要 expect正則表達式

2.  expect 命令介紹

  expect 是一個用來處理交互的命令。藉助 expect 能夠將交互過程寫在一個腳本里,就能夠實現自動化完成。上面的問題也能獲得解決。shell

形象來講,以下命令的交互都能獲得解決:bash

  1. ssh
  2. scp
  3. ftp

 

CentOS / RHEL 安裝 expect 服務器

# yum install expect -y

 

2.1 expect 中經常使用的命令

  expect 中最關鍵的四個命令: send 、 expect 、spawn 、 interact
ssh

  • send:用於向進程發送字符串
  • expect:從進程接收字符串
  • spawn:啓動新的進程
  • interact:容許用戶交互

 

(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

 

 

3. expect 使用實例

  expect 常常是做爲腳本出來的, 接下來經過我平常使用的幾個實例來講明:

 

3.1 expect scp的實現

  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

 執行結果:

 

3.2 expect ssh執行遠程命令

  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 和沒法鏈接互聯網的環境中。

相關文章
相關標籤/搜索