目录:
1.什么是Expect?
2.Expect程序工作流程
3.安装expect软件
4.先看一个expect小实例
5.Expect语法
5.1 spwan
5.2 expect
5.3 exp send t send
5.4 exp continue
5.5 send user
5.6 exit
6.expect变量
7.Expect关键字
7.1 eof
7.2 timeout
8.生产场景expect实战
8.1 实战1:使用expect实现批量分在/etc/hosts文件
8.2 实战2:使用expect实现批量分发ssh密钥文件
8.3 实战3:使用expect实现批量查看客户机负载,内存
9.有关expect的说明
1.什么是Expect?
Expect是基于Tcl的相对简单的一个免费的脚本编程语言,用来实现自动和交互式任务程序进行通信,无需人的手工干预。如ssh,ftp等,这些程序正常情况都需要手工与它们进行交互,而使用expect就可以模拟人手工交互的过程,实现自己的无端的程序交互,从而达到自动化运维的目的。
Expect是一个用来实现自动交互功能的软件套件(Expect is a software suite for automaing interactive tools)
虽然,使用C,perl等一样可以实现这样的交互功能,然而expect做的更专业出色,简单,而且除支持unit/linux平台外,还支持windows,它就是为系统管理和软件测试方面的自动交互类需求而产生的。
2.Expect程序工作流程
Expect的工作流程可以理解为,spawn启动进程-->expect期待关键字-->send向进程发送字符-->退出结束
3.安装Expect软件
首先,配置好yum安装源,并且确保机器可以上网,然后执行yum instal expect -y即可安装expect软件。
安装完后查看结果:
4.先看一个Expect小实例
#vim ssh164.exp (注意后缀为exp)
#!/usr/bin/expect(指定解释此脚本的shell)
spawn ssh 192.168.50.164 /sbin/ifconfig eth0(spawn:指定要执行的语句)
set timeout 60(设定超时时长,意思是要连接的IP,指定时间内无响应时,自断开)
expect "*password:"(匹配交互式提示的字符)
send "happy52121\n"(设置发送密码)
expect eof()
exit(执行后退出)
#chmod 700 ssh164.ex (添加执行权限)
#./ssh164.exp(从下图可以看出,无需要输入密码自动执行成功)
#expect ssh164.exp(这种方法也可以执行成功,但不能用. ssh164.exp的,这种调用的解释器是bash)
5.Expect语法
Expect中的命令是最重要的部分了,命令的使用语法如下:
命令 [选项] 参数
5.1 spawn
Spawn命令是expect的初始命令,它用于启动一个进程,之后所有expect操作都在这个进程中进行,如果没有spawn语句,整个expect就无法执行了,spawn使用方法如下:
在spawn命令后面,直接加上要启动的进程,命令等信息,除此之外,spawn还支持其它选项如:
-open 启动文件进程
-ignore忽略某些信号
5.2 expect
使用方法:
Expect 表达式 动作 表达式 动作 ....
Expect命令用于等候一个相匹配内容的输出,一旦匹配上就执行expect后面的动作或命令,这个命令接受几个特有的参数,用的最多的就是-re,表示使用正则表达式的方式匹配,使用起来就是这样:
spawn ssh root@192.168.50.164
expect “password:” { send “123456\r”} (后边是\r还是\n有待测试,貌似都可以,只要加特殊字符就行)
从上面的例子可以看出,expect是依附与spawn命令的,当执行ssh命令后,expect就匹配命令执行后的关键字:password:,如果匹配到关键字就会执行后面包含在{}括号中的send或者exp_send动作,匹配以及动作可以放在二行,这样就不需要使用{}括号了,就像下面这样,实际完成的功能与上面是一样的:
spawn ssh root@192.168.50.164
expect “password:”
send “123456\r”(后边是\r还是\n有待测试,貌似都可以)
expect命令还有一种用法,它可以在一个expect匹配中多次匹配关键字,并给出处理动作,只需要将关键字放在一个大括号中就可以了,当然还要有exp_continue.
spawn ssh root@192.168.50.164
expect {
“yes/no”{ exp_send “yes\r”;exp_continue }
“*password:” { exp_send “123456\r”}
}表示进行多次匹配,当匹配到第一次,还要进行第进行匹配时需要用到exp_continue
5.3 exp_send和send
在上面的介绍中,我们已经看到了exp_send命令的使用,exp_send命令是expect中的动作命令,它还有一个可以完成同样工作的同胞:send;exp_send命令可以发送一些特殊符号,我们看到的\r(回车),还有一些其它的比如:\n(换行),\t(制表符)等等,这些都是tcl中的特殊符号相同
spawn ssh root@192.168.50.164
expect {
“yes/no”{ exp_send “yes\r”;exp_continue }
“*password:” { exp_send “123456\r”}
}
5.4 exp_continue
这个命令一般用在动作中,它被使用的条件比较苛刻,看看下面的例子:
#!/usr/bin/expect
spawn ssh root@192.168.50.164 /sbin/ifconfig eth0
set timeout 60
expect {
-timeout 5 (设置超时时间,意思是在指定时间不给出结果,就断开)
"yes/no" { exp_send "yes\r";exp_continue}
"*password:" { exp_send "happy52121\r" };
timeout { puts "expect was timeout by test.";return} (当超时后,要打印出的内容)
}
expect eof
exit
在这个例子中,可以发现exp_continue命令的使用方法,首先它要处于一个expect命令中,然后它属于一种动作命令,完成的工作就是从头开遍历,也就是说如果没有这个命令,匹配第一个关键字以后就会继续匹配第二个关键字,但有了这个命令后,匹配第一个关键字以后,第二次匹配仍然从第一个关键字开始。
5.5 send_user
send_user命令用来把后面的参数输出到标准输出中去,默认的send,exp_send命令都是将参数输出到程序中的,用起来就像这样:
send_user “Please input passwd:”
这个语句就可以在标准输出中打印please input passwd:字符了。相当linux中的echo输出
5.6 exit
exit命令功能很简单,就是直接退出脚本,但是你可以利用这个命令对脚本做一些扫尾工作,比如下面这样:
exit -onexit {
exec rm $tmpfile(删除临时文件)
send_user “Good bye\n” (说再见,好玩)
}
6.Expect变量
expect中有很多有用的变量,它们的使用方法与TCL语言中的变量相同,比如:
set变量名变量值 #设置变量的方法
puts $变量名#读取变量的方法
例:接收命令行的参数作为自定义变量
7.Expect关键字
expect中的特殊关键字用于匹配过程,代表某些特殊含义或状态,一般用于expect族中命令中而不能在外面单独使用,也可以理解为事件,使用上类似于:
expect eof {}
7.1 eof
eof(end of file)关键字用于匹配结束符,比如文件的结束符,FTP传输停止等情况,在这个关键字后跟上动作来做进一步控制,特别是ftp交互操作方面,它的作用很大。用一个例子来看看:
spawn ftp anonymous@192.168.50.198
expect {
“password:” {exp_send “who I’M I”}
eof {ftp connect close}
}
interact {}
7.2 timeout
timeout是expect中的一个重要变量,它是一个全局性的时间控制开关,你可以通过为这个变量赋值来规定整个expect操作的时间,注意这个变量是服务与expect全局的,它不会纠缠于某一条命令,即使命令没有任何错误,到时间仍然会激活这个变量,但这个时间到达以后除了激活一个开关之外不会做其它的事情,如何处理脚本编写人员的事情,看看它的实际使用方法:
set timeout 60
spawn ssh root@192.168.50.198
expect “password:” {send “word\r”}
expect timeout {puts “Expect was timeout”;return}
上面的处理中,首先将timeout变量设置为60秒,当出现问题的时候程序可能会停止下来,只要到60秒就会激活下面的的timeout动作,这里我打印一个信息并且停止了脚本的运行------你可以做更多其它的事情,看自己的意思。
在另一种expect格式中,我们还有一种设置timeout变量的方法,看看下面的例子“
spawn ssh root@192.168.50.198
expect {
-timeout 60
-re “password:” {exp_send “word\r”}
-re “TopsecOS#” { }
timeout {puts “Expect was timeout”;return}
}
在expect命令中间加上一个小横杠,也可以设置timeout变量
timeout变量中,设置为0表示立即超时,-1则表示永不超时。
8.生产场景Expect实战
a.把文件传递到某台主机的某个目录下,要向脚本传递3个参数
#!/usr/bin/expect
if {$argc!=3} {//判断命令行是否给到3个参数
send_user "Usage:expect need three arguments lisk thks:file host dir\n"
exit
}
set srcname [lindex $argv 0]//取到命令行的第1个参数,并传递给变量
set hostname [lindex $argv 1]//取到命令行的第2个参数,并传递给变量
set destname [lindex $argv 2]//取到命令行的第3个参数,并传递给变量
set password "123456"
spawn scp $srcname root@$hostname:$destname
set timeout 60
expect {
-timeout 2
"yes/no" {send "yes\r";exp_continue}
"*password:" {send "happy52121\r"}
timeout {puts "expect connect failure,please contact admin.";return}
}
expect eof
exit -onexit {
send_user "Jobs has finished,Goodbye.\n"
}
b.使用expect实现批量分发/etc/hosts文件
在上面例子的基础上做一些修改,使其可以实现批量分发文件
#vim scp.sh
#!/bin/bash
iplist=(//把想要操作的IP,定义成一个数组,当然也可以单独写到一个文件中,调用时用`cat iplist`即可
192.168.50.198
192.168.50.164
192.168.50.165
)
for ip in ${iplist[*]}//${iplist[*]}引用数组中的每一个元素
do
expect scp.exp /etc/fstab $ip /tmp
done
#. scp.sh//可以看到定义的几台IP中,复制操作全部执行成功
再做一些修改使其更专业一点:通过调用/etc/init.d/functions
#vim scp.sh (///bin/ture,表示OK,/bin/false表示FAILED,在开机启动的时候的你可以看到很多选项后都有)
#. scp.sh //这样看是不是要专业很多呢
不过这样做会有一个问题,因为我在scp.exp文件中对连接超时的情况做过处理,这样造成的结果就是不存的IP 也会执行成功(我现在添加一个并不存在的IP192.168.50.256,果看结果也是OK
所以此时就需要在scp.exp中,把连接超时的情况不做处理,这样在执行scp.sh时就会返回值为1
把超时处理的情况注释掉,可以看到那个不存的IP处理失败
本文转自激情燃烧的岁月博客51CTO博客,原文链接http://blog.51cto.com/liuzhengwei521/1752415如需转载请自行联系原作者
weilovepan520