expect自动化交互式程序应用实践
1、什么是 expect
expect 是一个用来实现自动交互功能的软件套件,是基于 TCL 的脚本编程工具语言,方便学习,功能强大。
2、为什么要用 expect
2.1 案例
[root@CentOS8 ~]# ssh -p22 root@10.110.81.223 uptime The authenticity of host '10.110.81.223 (10.110.81.223)' can't be established. ECDSA key fingerprint is SHA256:a90cAgsNSIkK3nh1uJ08NtYyo+8UMqZ/5TtdXplIgkY. Are you sure you want to continue connecting (yes/no)? yes # 如果是第一次,那么这里还得有RSA KEY的yes/no选项
Warning: Permanently added '10.110.81.223' (ECDSA) to the list of known hosts. root@10.110.81.223's password: 06:51:05 up 33 days, 15:48, 2 users, load average: 0.88, 0.68, 0.70
2.2 描述
可以发现上述案例中,使用 SSH 远程连接服务器时,第一次连接要和系统实现两次交互。
简单来说,expect 是用来自动实现与交互式程序通信的,而无需管理员的手工干预,从而达到自动化运维的目的。
2.3 以下是 expect 的自动交互工作流程简单说明
spawn 启动制定进程->expect 获取期待的关键字->send 向指定进程发送指定字符-> 进程执行完毕,退出结束。
3、安装 expect
[root@bogon xls-a]# rpm -qa expect [root@bogon xls-a]# yum install -y expect [root@bogon xls-a]# rpm -qa expect expect-5.44.1.15-5.el6_4.x86_64
4、案例
4.1 案例 1-expect1
[root@CentOS8 test]# cat boxiaoyaun.exp #!/usr/bin/expect # 脚本开头解析器,和shell类似,表示程序使用Expect解析 spawn ssh -p22 root@10.110.81.223 uptime # 执行ssh命令(注意开头必须要有spawn,否则无法实现交互) expect "*password*" # 利用expect获取执行上述ssh命令输出的字符串是否为脐带的字符串 send "密码\n" expect eof
[root@CentOS8 test]# expect boxiaoyaun.exp spawn ssh -p22 root@10.110.81.223 uptime root@10.110.81.223's password: 06:55:30 up 33 days, 15:53, 2 users, load average: 0.30, 0.44, 0.59
注释:
1)在expect自动交互程序执行的过程中,spawn命令是一开始就需要使用的命令,通过spawn执行一个命令或程序,之后所有的expect操作都会在这个执行过的命令或程序进程中进行,包括自动交互功能,因此如果没有spawn命令,expect程序将会无法实现自动交互。
2)使用spawn命令是expect程序实现自动交互工作流程中的第一步,也是最关键的一步。
4.2 案例 2-expect2
[root@bogon exp]# cat 18_2_1.exp #!/usr/bin/expect spawn ssh -p22 tomcat@10.10.8.17 uptime expect { # 前始大括号要有空格 "yes/no" {exp_send "yes\r";exp_continue} "*password" {exp_send "填写你的服务器密码\r"} } expect eof [root@bogon exp]# rm -rf ~/.ssh/known_hosts [root@bogon exp]# expect 18_2_1.exp spawn ssh -p22 tomcat@10.10.8.17 uptime The authenticity of host '10.10.8.17 (10.10.8.17)' can't be established. RSA key fingerprint is 02:c1:55:f6:9c:fd:5f:66:a5:e0:1b:51:ef:2d:c1:0d. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '10.10.8.17' (RSA) to the list of known hosts. tomcat@10.10.8.17's password: 15:39:22 up 2 days, 3:56, 1 user, load average: 0.08, 0.06, 0.05
注释:
1)expect{},类似多行expect
2)exp_send和send类似,后面的\r(回车)和前文\n(换行)类似。
3)匹配多个字符串,需要在每次匹配并执行动作后,加上exp_continue,即让expect程序继续匹配,注意exp_continue前面的分号";"。
4.3 案例 3-read-exp_send-send
利用 expect 响应 shell 脚本中的多个 read 读入
#注意下面的单引号和双引号。 [root@bogon exp]# cat 18_3_1.sh #!/bin/sh read -p 'input username :' name read -p 'input password :' pass read -p 'input email :' email echo -n "your name is $name," echo -n "your pass is $pass," echo -n "your email is ${email}." [root@bogon exp]# /bin/sh 18_3_1.sh input username :nameval input password :passval input email :emailval your name is nameval,your pass is passval,your email is emailval.
注释: exp_send和send都是expect中的动作命令,用法类似,即在expect命令匹配指定的字符串后,发送指定的字符串给系统。
[root@bogon exp]# cat 18_3_2.exp #!/usr/bin/expect spawn /bin/sh 18_3_1.sh expect { "username" {exp_send "testname\r";exp_continue} "*pass*" {send "123456\r";exp_continue} "*mail*" {exp_send "123456@qq.com\r"} } expect eof [root@bogon exp]# expect 18_3_2.exp spawn /bin/sh 18_3_1.sh input username :testname input password :123456 input email :123456@qq.com your name is testname,your pass is 123456,your email is 123456@qq.com.
4.4 案例 4-send_user
[root@bogon exp]# cat 18_4_1.exp #!/usr/bin/expect send_user "i am boy.\n" send_user "i am linux.\n" send_user "blog is llyweb.\n" [root@bogon exp]# expect 18_4_1.exp i am boy. i am linux. blog is llyweb.
注释: send_user命令可用来打印expect脚本信息,类似shell的echo命令。
4.5 案例 5-exit
[root@bogon exp]# cat 18_4_2.exp #!/usr/bin/expect send_user "i am boy.\n" send_user "i am linux.\n" send_user "blog is llyweb.\n" exit -onexit { send_user "good bye.\n" } [root@bogon exp]# expect 18_4_2.exp i am boy. i am linux. blog is llyweb. good bye.
注释: exit命令类似于shell中的exit,即直接退出expect脚本,除了最基本的退出脚本功能以外, 还可以利用这个命令对脚本做一些关闭前的清理和提示等工作。
4.6 案例 6-普通变量
[root@bogon exp]# cat 18_6_1.exp #!/user/bin/expect set password "123456" puts $password # 打印变量 send_user "${password}.\n" [root@bogon exp]# expect 18_6_1.exp 123456 123456.
4.7 案例 7-特殊参数变量
[root@bogon exp]# cat 18_8_1.exp #!/usr/bin/expect set file [lindex $argv 0] set host [lindex $argv 1] set dir [lindex $argv 2] puts "$file\t$host\t$dir" puts $argc puts $argv0 [root@bogon exp]# expect 18_8_1.exp yijiananzhuang.sh 10.10.8.17 /home/tomcat/yijiananzhuang yijiananzhuang.sh 10.10.8.17 /home/tomcat/yijiananzhuang 3 18_8_1.exp
注释: 在expect中$argv表示参数数组,可以使用[lindex $argv n]接收expect脚本传参。 $argc表示传参的个数 $argv0表示脚本的名字。
4.8 案例 8-if-else
[root@bogon exp]# cat 18_10_1.exp #!/usr/bin/expect if {$argc != 26} { puts "bad." } else { puts "good." } [root@bogon exp]# expect 18_10_1.exp bad. [root@bogon exp]# expect 18_10_1.exp {a..z} good.
说明:if关键字后面要有空格,else关键字前后都要有空格,{条件表达式}大括号里面靠近大括号处可以没有空格,将指令括起来的起始大括号"{"前要有空格。
4.9 案例 9-关键字-eof-timeout
注释:
expect 中的特殊关键字用于匹配过程,代表某些特殊的含义或状态,一般只用于 expect 命令中而不能在 expect 命令外单独使用。
[root@bogon exp]# cat 18_1_1.exp #!/usr/bin/expect spawn ssh -p22 tomcat@10.10.8.17 uptime expect "*password*" send "填写你的服务器密码\n" expect eof [root@bogon exp]# expect 18_1_1.exp spawn ssh -p22 tomcat@10.10.8.17 uptime tomcat@10.10.8.17's password: 21:41:17 up 3 days, 9:58, 1 user, load average: 0.02, 0.04, 0.05
注释:eof关键字用于匹配结束符。
timeout是expect中的一个控制时间的关键字变量,它是一个全局性的时间控制开关,
可以通过为这个变量赋值来规定整个expect操作的时间,注意这个变量是服务于expect全局的,
而不是某一条命令,即使命令没有任何错误,到了时间仍然会激活这个变量,
此外,到时间后还会激活一个处理及提示信息开关。
[root@bogon exp]# cat 18_11_1.exp #!/usr/bin/expect spawn ssh tomcat@10.10.8.17 uptime #设置10秒超时 set timeout 10 expect "yes/no" expect timeout [root@bogon exp]# expect 18_11_1.exp spawn ssh tomcat@10.10.8.17 uptime tomcat@10.10.8.17's password:
注释:timeout设置为0表示立即超时,-
1表示永不超时。
[root@bogon exp]# cat 18_11_2.exp #!/usr/bin/expect spawn ssh tomcat@10.10.8.17 uptime expect { -timeout 3 "yes/no" {exp_send "yes\r";exp_continue} timeout {puts "request timeout by boy.";return} } [root@bogon exp]# expect 18_11_2.exp spawn ssh tomcat@10.10.8.17 uptime tomcat@10.10.8.17's password: request timeout by boy.
5、生产模拟案例
5.1 案例 1-uptime-"free -m"
[root@bogon exp]# cat 18_12_1.exp #!/usr/bin/expect if { $argc != 2 } { puts "usage: expect $argv0 ip command" exit } #define var set ip [lindex $argv 0] set cmd [lindex $argv 1] set password "填写你的服务器密码" spawn ssh tomcat@$ip $cmd expect { "yes/no" {send "yes\r";exp_continue} "*password" {send "$password\r"} } [root@bogon exp]# expect 18_12_1.exp 10.10.8.17 uptime spawn ssh tomcat@10.10.8.17 uptime tomcat@10.10.8.17's password: 17:35:35 up 2 days, 5:52, 1 user, load average: 0.01, 0.09, 0.08 [root@bogon exp]# expect 18_12_1.exp 10.10.8.17 "free -m" spawn ssh tomcat@10.10.8.17 free -m tomcat@10.10.8.17's password: total used free shared buff/cache available Mem: 7731 205 7260 9 265 7257 Swap: 7935 0 7935