有需求,在容許命令或者腳本跳出交互行,須要進行內容輸入,但須要人手動輸入,不是很方便,此時能夠經過expect來實現自動互動交互。shell
expect是一個自動交互功能的工具,能夠知足代替咱們實際工做中須要從終端手動輸入某些內容來使得程序或命令繼續運行的目的。如安裝軟件是時的一些提示,ssh遠程主機執行命令時須要屢次輸入密碼的狀況。bash
yum install tcl -y
yum install expect -y
#!/usr/bin/expect set timeout 30 set host "192.168.200.221" set username "root" set password "123456" spawn ssh $username@$host ls expect "password" {send "$password\r"} expect eof interact
#!/usr/bin/expect: 表示使用expect來解釋該腳本。ssh
set timeout 30: 表示設置超時時間,這裏是表示超時時間爲30秒,默認爲10秒,用於執行shell命令的時間,若是執行的shell命令時間較長(如傳輸文件),則須要設置長一點。ide
set username "root" : 表示設置並定義了變量username,變量值爲"root"。工具
spawn ssh $username@$host ls: 表示使用spawn
來執行ssh $username@$host ls
命令,該命令只有在expect環境裏才能執行,因此直接在命令行輸入或沒有安裝expect則會報錯,它的主要功能是給它後面的shell命令運行進程加了個殼,進行傳遞交互的內容,注意,若是用引號將變量引發,將可能致使錯誤extra characters after close-quote...。oop
expect "password": 表示從spawn
執行的命令的進程裏接受字符串,通常是彈出終端的交互行的標準輸入提示信息,如須要你肯定時的(yes/no?),須要你輸入密碼的(...password:)。這裏由於ssh命令的交互內容是叫你輸入密碼,交互提示的內容有password,因此這裏匹配password。spa
end $password\r表示當expect
匹配成功,就把$password
發送給spawn
執行的命令的進程,完成交互,至關於手動輸入$password
,這裏的\r表明回車,也可使用\n。.net
expect eof: 表示結束expect
,讀取到文件結束符 ,當spawn發送指令到終端執行時在返回時被expect捕捉時,在起始會有一個eof,就比如在shell中 cat >>file <<EOF... EOF
同樣,在結束時也要有eof;expect eof
有時間限制,即咱們設置的超時時間,默認10秒,不過可能出現的問題是,若是是在傳輸一個大文件,可能在文件還沒傳輸完成便斷開了命令執行,此時須要設置超時時間長一點,或將expect eof
改爲expect -timeout -1 eof
。命令行
interact: 執行完命令後,控制權交互控制檯,此時再有交互,expect將不會進行交互,須要手動進行輸入內容交互。若是沒有這句,在須要交互的ssh命令執行完畢後將會退出遠程,而不是繼續保持在遠程。rest
$argc
:表示命令行參數個數[lindex $argv n]
:表示index爲n的參數(index從0開始計算),index的區間爲左閉右開,如[lindex $argv 0]
表明命令行輸入的第一個參數,[lindex $argv 0 3]
表明命令行輸入的第一到第三個參數 。#!/usr/bin/expect set host [lindex $argv 0] set username [lindex $argv 1] set num $argc if { num < 3 } { ... }
if {條件1} { expect { "(yes/no)" { send "yes\r" expect "*assword:" {send "$password\r"} } "password" { send "$password\r" } } else { puts "Expect was timeout" send_user "Expect was timeout" }
expect {}: 多行指望,從上往下匹配,匹配成功裏面的哪一條,將執行與之的send
命令
puts與send_user: 打印信息,相似echo
其餘:
for {set i 0} {$i < 10} {incr i} { puts "I inside first loop: $i" }
set i 0 while {$i < 10} { puts "I inside third loop: $i" incr i puts "I after incr: $i" }
incr: 遞增運算符 incr i ,相似++
-re
選項,expect -re "\\\[(.*)]" 其中[在expect shell 正則中都有特殊意義,所以要\三次exp_continue
: 循環匹配,一般匹配以後會退出語句,但使用exp_continue
則能夠不斷循環執行某段語句
expect { "password" { send "$password\r" exp_continue # 不斷匹配字符串"password",只要匹配成功就send } } expect eof
shell 嵌套使用expect,使用重定向,須要注意EOF之間的互相對應
#!/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"} } "password" { send "$password\r" } } expect eof EOF # 因爲用的-EOF,這裏的EOF能夠有空格,tab鍵
excpet中執行shell語句,exec sh -c {shell語句}
,多用於賦值變量,須要注意的是,expect裏執行的shell語句,即便有打印和交互內容(echo,read命令)也不會輸出到終端,即執行了命令,你並不知道是否出錯,也不知道執行結果,若是須要將shell中echo命令打印的內容輸出到終端,只能將執行結果賦值給expect變量,再使用puts命令打印出來,但即便這樣,也會出現一些莫名頭疼的問題,因此儘可能不要在expect中調用複雜的shell語句。
exec sh -c {shell 命令} # 執行的shell命令即便有打印和須要交互的內容也不會出如今終端 set test_echo [exec sh -c {echo "test"}] puts "$test_echo"
expect/shell互相使用彼此變量
#!/bin/bash
解釋的shell文件,expect調用shell變量直接$變量
,和shell腳本調用變量方式並沒有異同,使用#!/usr/bin/expect
解釋的expect腳本文件,shell做爲expect文件的語句,如set a [exec sh -c {echo \$LAB}]
調用expect變量,須要在expect裏面設置環境變量,如:set ::env(LAB) my_lab
./test.excp
,首先須要在shell中進行變量export, 例如export a="test"
, 而後在expect腳本文件中經過 $::env(a) 引用shell腳本文件的變量,例如set a_exp \$::env(a)
,同時也能夠經過執行子shell調用,例如:set a [exec sh -c {echo $a}]
向進程發送Ctcl + c
,若是想向遠端發送Ctrl-C結束遠端進程,能夠經過send "\003" 實現
參考博客: