1. expect介紹
使用Linux的程序員對(duì)輸入密碼都不會(huì)陌生姑丑,比如使用超級(jí)用戶執(zhí)行命令,又比如scp
辞友、ssh
連接遠(yuǎn)程主機(jī)等等栅哀。如果我們腳本里面有scp
的操作,總不可能執(zhí)行一次scp
就輸入密碼一次称龙,這樣就需要一個(gè)人盯著腳本運(yùn)行了留拾。 為了解決這個(gè)問(wèn)題,我們需要一個(gè)自動(dòng)輸入密碼的功能鲫尊。
expect
是建立在tcl(Tcl/Tk快速入門 )基礎(chǔ)上的一個(gè)工具痴柔,它可以讓一些需要交互的任務(wù)自動(dòng)化地完成。相當(dāng)于模擬了用戶和命令行的交互操作疫向。
一個(gè)具體的場(chǎng)景:遠(yuǎn)程登陸服務(wù)器咳蔚,并執(zhí)行命令
登錄時(shí)輸入密碼需要交互豪嚎,bash腳本無(wú)法完成,可以使用expect來(lái)完成谈火。
2. 安裝
brew install expect
3. 原理
首先使用 spawn
開啟一個(gè)會(huì)話侈询,然后使用 expect-send
對(duì)來(lái)執(zhí)行交互式操作。
spawn
后面跟上一個(gè)命令操作堆巧,表示開啟一個(gè)會(huì)話妄荔。expect
等待輸出特定的字符串(通常是提示符),然后使用send
發(fā)送交互字符串谍肤。比如:
spawn ssh username@host # 遠(yuǎn)程登錄
expect "*assword" # 提示為:"username@host's password:", 等待用戶輸入密碼
send "${password}\r" # 這時(shí)使用send模擬用戶輸入密碼的字符串啦租,完成登錄驗(yàn)證
4. 基本語(yǔ)法
腳本解釋器
腳本中首先引入文件,表明使用的是哪一個(gè)shell
#!/usr/bin/expect
set
設(shè)置會(huì)話超時(shí)時(shí)間為30s, 若不限制超時(shí)時(shí)間則應(yīng)設(shè)置為-1
set timeout 30
set 還可以設(shè)置變量
# 使用變量語(yǔ)句:$param 或者 ${param}({}用來(lái)避免param和后面的字符串拼接起來(lái)導(dǎo)致錯(cuò)誤)
set param "param_str"
set param 1
spawn
spawn 后面跟一個(gè)命令荒揣,開啟一個(gè)會(huì)話
spawn ${cmd} # for example : spawn su root
expect - send
expect
接收命令執(zhí)行后的輸出篷角,然后和期望字符串匹配,若對(duì)應(yīng)這執(zhí)行相應(yīng)的send
來(lái)發(fā)送交互信息系任。
expect "$case1" {send "$respond1\r"} # 這一行等同于下面兩行
expect "$case1"
send "$response1\r"
expect 可以有多個(gè)分支恳蹲,就像switch語(yǔ)句一樣。
expect
{
"$case1" {send "$response1\r"}
"$case2" {send "$response2\r"}
"$case3" {send "$response3\r"}
}
結(jié)束符
expect eof
:等待執(zhí)行結(jié)束俩滥,若沒有這一句嘉蕾,可能導(dǎo)致命令還沒執(zhí)行,腳本就結(jié)束了
interact
: 執(zhí)行完成后保持交互狀態(tài), 這時(shí)可以手動(dòng)輸入信息
注:expect eof
與 interact
二選一即可
接收參數(shù)
參數(shù)存在argv中霜旧,使用第一個(gè)參數(shù)如下:
set param0 [lindex $argv 0]
$argc
表示參數(shù)個(gè)數(shù)错忱,判斷語(yǔ)句如下:
if {$argc < 1} {
#do something
send_user "usage: $argv0 <param1> <param2> ... "
exit
}
注:$argv0
是腳本名,但[lindex $argv 0]
是第一個(gè)參數(shù) param1挂据, [lindex $argv 1]
是第二個(gè)參數(shù) param2, 以此類推 send_user 用來(lái)顯示信息到父進(jìn)程(一般為用戶的shell)的標(biāo)準(zhǔn)輸出以清。
5. 實(shí)例
實(shí)現(xiàn)遠(yuǎn)程登錄服務(wù)器,并切換到root用戶下執(zhí)行關(guān)閉防火墻的命令崎逃,然后退出
#!/usr/bin/expect
if {$argc < 4} {
#do something
send_user "usage: $argv0 <remote_user> <remote_host> <remote_pwd> <remote_root_pwd>"
exit
}
set timeout -1
set remote_user [lindex $argv 0] # 遠(yuǎn)程服務(wù)器用戶名
set remote_host [lindex $argv 1] # 遠(yuǎn)程服務(wù)器域名
set remote_pwd [lindex $argv 2] # 遠(yuǎn)程服務(wù)器密碼
set remote_root_pwd [lindex $argv 3] # 遠(yuǎn)程服務(wù)器根用戶密碼
# 遠(yuǎn)程登錄
spawn ssh ${remote_user}@${remote_host}
expect "*assword:" {send "${remote_pwd}\r"}
expect "Last login:"
# 切換到 root
send "su\r"
expect "*assword:" {send "${remote_root_pwd}\r"}
# 執(zhí)行關(guān)閉防火墻命令
send "service iptables stop\r"
send "exit\r"
send "exit\r"
expect eof
將代碼保存到 remot_root_command.exp 中掷倔,權(quán)限改為755,然后執(zhí)行下面這條命令即可:
./remote_root_command.exp <remote_user> <remote_host> <remote_pwd> <remote_root_pwd>