您好,登錄后才能下訂單哦!
? shell腳本存在的核心意義就在于基于shell命令簡(jiǎn)化甚至省略可避免的人工操作,通過各種控制流程結(jié)構(gòu)以及正則表達(dá)式等方法,逐步實(shí)現(xiàn)自動(dòng)化操作的整個(gè)過程,由此也可見,shell并沒有面向?qū)ο蟮乃枷耄愃艭語(yǔ)言,畢竟C語(yǔ)言是操作系統(tǒng)或者說(shuō)是內(nèi)核的核心語(yǔ)言。
? 所以,語(yǔ)言并無(wú)優(yōu)劣之分,只是每個(gè)人使用的習(xí)慣與方式不同,換句話說(shuō),難易的不是語(yǔ)言,而是思想與突如其來(lái)的靈感。
? Expect是建立在TCL基礎(chǔ)上的一個(gè)工具,Expect是用來(lái)進(jìn)行自動(dòng)化控制和測(cè)試的工具。主要解決shell腳本中不可交互的問題。對(duì)于大規(guī)模的Linux運(yùn)維很有幫助。
? 在Linux運(yùn)維和開發(fā)中,我們經(jīng)常需要遠(yuǎn)程登錄服務(wù)器進(jìn)行操作,登錄的過程是一個(gè)交互過程,需要輸入yes/no password等信息。為了模擬這種輸入,可以使用Expect腳本。
send:向進(jìn)程發(fā)送字符串,用于模擬用戶的輸入,但不支持換行 一般需要加上 \r
expect:內(nèi)部命令
? 判斷上次輸出結(jié)果里是否包含指定的字符串,有則返回,反之就等待超時(shí)時(shí)間后返回。
? 只能捕捉由spawn啟動(dòng)的進(jìn)程的輸出。
spawn:?jiǎn)?dòng)進(jìn)程,并跟蹤后續(xù)交互信息。
Timeout:指定超時(shí)時(shí)間,過期則繼續(xù)執(zhí)行后續(xù)指令
exp_continue——允許expect繼續(xù)向下執(zhí)行指令(比較關(guān)鍵,多次交互)
send_user——回顯命令,相當(dāng)于echo
expect [選項(xiàng)] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
選項(xiàng)
-c:從命令行執(zhí)行expect腳本,默認(rèn)expect是交互地執(zhí)行的
示例:expect -c 'expect "\n" {send "pressed enter\n"}
-d:可以輸出輸出調(diào)試信息
示例:expect -d ssh.exp
expect最常用的語(yǔ)法(tcl語(yǔ)言:模式-動(dòng)作)
單一分支模式語(yǔ)法:
expect “hi” {send “You said hi\n"} 匹配到hi后,會(huì)輸出“you said hi”,并換行,也可以使用\r
多分支模式語(yǔ)法:
expect "hi" { send "You said hi\n" } \ "hehe" { send “Hehe yourself\n" } \ "bye" { send “Good bye\n" }
匹配hi,hello,bye任意字符串時(shí),執(zhí)行相應(yīng)輸出.等同如下:
expect { "hi" { send "You said hi\n"} "hehe" { send "Hehe yourself\n"} "bye" { send “Good bye\n"} }
[root@lokott ~]# yum install -y expect
已加載插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
...//省略部分
[root@lokott shell]# cat a.sh
#使用which expect查看其位置
#!/usr/bin/expect
#設(shè)置超時(shí)時(shí)間
set timeout 20
log_file test.log
log_user 1
#變量定義
set hostname [lindex $argv 0]
set passwd [lindex $argv 1]
#啟動(dòng)進(jìn)程,spawn監(jiān)控
spawn ssh root@$hostname
#匹配條件
expect {
"(yes/no)"
#exp_continue表示繼續(xù)向下匹配
{send "yes\r";exp_continue}
"*password"
{send "$passwd\r"}
}
#轉(zhuǎn)交權(quán)限給控制臺(tái)
interact
[root@lokott shell]# ./a.sh 192.168.68.129 123456 //第一次登錄
spawn ssh root@192.168.68.129
The authenticity of host '192.168.68.129 (192.168.68.129)' can't be established.
ECDSA key fingerprint is SHA256:k/6W9M/dgxVrbMgSx9nIFPGfVgUfLMoIb27ys9ZF+LM.
ECDSA key fingerprint is MD5:26:dd:06:b3:32:bd:d6:a3:2f:7c:66:7d:b9:c0:4b:c4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.68.129' (ECDSA) to the list of known hosts.
root@192.168.68.129's password:
Last login: Wed Dec 4 10:24:33 2019 from 192.168.68.1
[root@localhost ~]# exit
登出
Connection to 192.168.68.129 closed.
[root@lokott shell]# ./a.sh 192.168.68.129 123456 //第二次登錄上一次登錄需要的秘鑰已經(jīng)保存
spawn ssh root@192.168.68.129
root@192.168.68.129's password:
Last login: Wed Dec 4 10:29:42 2019 from 192.168.68.130
[root@localhost ~]# exit
登出
Connection to 192.168.68.129 closed.
上述演示的是直接使用expect腳本實(shí)現(xiàn)ssh遠(yuǎn)程登錄的操作過程,而expect腳本也可以被嵌入到普通的腳本文件中,下面給出具體演示:
[root@lokott shell]# cat b.sh
#嵌入expect執(zhí)行實(shí)現(xiàn)免交互登錄
#!/bin/bash
#定義普通變量,在該shell腳本中始終有效
hostname=$1
passwd=$2
#嵌入寫入expect腳本內(nèi)容??實(shí)現(xiàn)免交互的具體內(nèi)容
/usr/bin/expect<<-EOF
spawn ssh root@$hostname
expect {
"(yes/no)"
{send "yes\r";exp_continue}
"*password"
{send "$passwd\r";}
}
#下兩行是為了返回本地控制臺(tái)的操作演示
expect "*]#"
send "exit\r"
expect eof
EOF
#注意EOF的前后都不可以有空格?。?!
[root@lokott shell]# ./b.sh 192.168.68.129 123456
spawn ssh root@192.168.68.129
root@192.168.68.129's password:
Last login: Wed Dec 4 12:22:23 2019 from 192.168.68.130
[root@localhost ~]# exit
登出
Connection to 192.168.68.129 closed.
推薦使用這種方式,因?yàn)樵趯?shí)際使用中一般都是在普通腳本中使用expect的,所有嵌入寫入比較方便,比較常用!
直接使用expect免交互的完整腳本如下,有興趣可以試著改為嵌入寫入的代碼:
[root@lokott shell]# cat ssh.sh
#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh root@$hostname
expect {
"No route to host" exit
"Invalid argument" exit
"Connection refused" exit
"Name or service not known" exit
"to continue" {send "yes\r";exp_continue}
"password:" {send "$password\r"}
}
interact
exit
[root@lokott shell]# ./ssh.sh 192.168.68.133 123456 //服務(wù)器非在線
spawn ssh root@192.168.68.133
ssh: connect to host 192.168.68.133 port 22: No route to host
[root@lokott shell]# ./ssh.sh 123456 //參數(shù)輸入錯(cuò)誤
spawn ssh root@123456
ssh: connect to host 123456 port 22: Invalid argument
[root@lokott shell]# ./ssh.sh 192.168.68.129 123456 //正常登錄
spawn ssh root@192.168.68.129
root@192.168.68.129's password:
Last login: Wed Dec 4 15:20:51 2019 from 192.168.68.130
[root@localhost ~]#
[root@lokott shell]# cat c.sh
#!/bin/bash
username=$1
password=$2
useradd $1
[ $? -eq 0 ]&&echo ||exit 1
/usr/bin/expect<<-EOF
spawn passwd ${username}
expect {
"密碼:"
{send "${password}\r";exp_continue}
"密碼:"
{send "${password}\r";}
}
EOF
tail -1 /etc/shadow|awk -F: '{print $1,$2}'
userdel -r $1
#執(zhí)行結(jié)果如下
[root@lokott shell]# ./c.sh zhazhahui 123456
spawn passwd zhazhahui
更改用戶 zhazhahui 的密碼 。
新的 密碼:
無(wú)效的密碼: 密碼少于 8 個(gè)字符
重新輸入新的 密碼:
passwd:所有的身份驗(yàn)證令牌已經(jīng)成功更新。
zhazhahui $6$k.MdzCd3$XMUGf5XQV4sE5RJqcwdEoOkd8UVgWtwcguzi6Md5yXcagYvgyE8GmCjzjxkEB5rXR.IRG9j49c36amzkDIe5l1
? 本文主要介紹了expect實(shí)現(xiàn)免交互的作用以及結(jié)合實(shí)際案例講解其兩種使用方式(直接和嵌入)的具體操作過程。
? 過程主要分為:基本變量定義(timeout最好最先設(shè)置)——spawn啟動(dòng)跟蹤——expect匹配——interact交付控制權(quán)(沒有會(huì)退出)或者expect eof 結(jié)束expect匹配。
? 務(wù)必結(jié)合上述的案例自己多使用體會(huì)理解!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。