Expect的原理与工作机制

首先使用 spawn 开启一个会话,然后使用 expect-send 对来执行交互式操作。
spawn 后面跟上一个命令操作,表示开启一个会话。expect 等待输出特定的字符串(通常是提示符),然后使用send 发送交互字符串。

例如:
spawn ssh username@host   #远程登录支持ssh ftp http sftp scp等
expect "*assword"                  #提示为:"username@host's password:", 等待用户输入密码
send "password\r"             #这时使用send模拟用户输入密码的字符串,完成登录验证 (\r发送一个回车)
exp_continue:可以继续执行下面的匹配,匹配不见得必需要匹配最后几个字符

1. 基本语法介绍
脚本解释器
脚本中首先引入文件,表明使用的是用哪一个程序运行该脚本

#!/usr/bin/expect

# set:设置会话超时时间为30s, 若不限制超时时间则应设置为-1
set timeout 30

#set还可以设置变量
# 使用变量语句:$param 或者 ${param} (说明:{ }用来避免param和后面的字符串拼接起来导致错误)
set param "param_str" #设置一个param变量,变量值为param_str

# spawn后面跟一个命令,开启一个会话,例:spawn ${cmd} # for example : spawn su root
#expect 接收命令执行后的输出,然后和期望字符串匹配,若对应这执行相应的send来发送交互信息。

expect "$case1" {send "$respond1\r"} # 这一行等同于下面两行
expect "$case1"
send "$response1\r"

#expect 可以有多个分支,就像switch语句一样
expect
{
"$case1" {send "$response1\r"}
"$case2" {send "$response2\r"}
"$case3" {send "$response3\r"}
}

结束符
expect eof :等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
interact : 执行完成后保持交互状态, 这时可以手动输入信息

接收参数
参数存在于argv中,设置第一个参数如下:
set param0 [lindex $argv 0]

$argc表示参数个数,判断语句如下:
if {$argc < 1} {
#do something
send_user "usage: $argv0 <param1> <param2> ... "
exit
}

注:$argv0是脚本名,$argc表示参数的个数
[lindex $argv n]用来接收输入的脚本参数,n从0开始,分别表示第一个,第二个,第三个....参数,
[lindex $argv 0]是第一个参数也可以用[lrange $argv 0 0]表示, [lindex $argv 1]或者[lrange $argv 1 1]都可以表示第二个参数, 以此类推
[lrange $argv 0 4]表示第一个参数到第五个参数
send_user 用来显示信息到父进程(一般为用户的shell)的标准输出。

2. 实例
实现远程登录服务器,并切换到root用户下执行关闭防火墙的命令,然后退出

#!/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]            # 远程服务器用户名
set remote_host [lindex $argv 1]            # 远程服务器域名
set remote_pwd [lindex $argv 2]            # 远程服务器密码
set remote_root_pwd [lindex $argv 3]   # 远程服务器根用户密码

# 远程登录
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"}

# 执行关闭防火墙命令
send "service iptables stop\r"
send "exit\r"
send "exit\r"
expect eof

将以上代码保存到first.exp 中,权限改为755
expect脚本执行方法:
./first.exp <remote_user> <remote_host> <remote_pwd> <remote_root_pwd>
expect first.exp <remote_user> <remote_host> <remote_pwd> <remote_root_pwd>

 

[root@web ~]# cat first.exp
#!/usr/bin/expect -d
set timeout 5
set user [lrange $argv 0 0]
set ipaddr [lrange $argv 1 1]
set password [lrange $argv 2 2]
spawn ssh $user@$ipaddr
expect {
"yes/no" {send "yes\r";exp_continue}       #exp_continue(如没匹配成功可继续执行下面的匹配)
"password:" {send "$password\r"}
}
expect "#"
send "touch a.txt\r"
send "exit\r"
expect eof
exit

注意:脚本里使用的expect、send、spawn、interact都是expect解释器的内部命令,shell里没有

如果你在第一行(#!/usr/bin/expect)使用-d (debug参数),可以在运行的时候输出一些很有用的信息

 

posted @ 2017-12-19 15:18  風£飛  阅读(22)  评论(0)    收藏  举报