本文主要讲解 Shell 脚本开发中 Expect 自动化交互式程序的应用实践
目录:
1.Expect 介绍
2. 安装 Expect 软件和简单实现交互功能
3.Expect 程序自动交互的重要命令及实践
4.Expect 程序变量介绍
一: Expect 介绍
1) 什么是 Expect
Expect 是一个用来实现自动交互功能的软件套件, 是基于 TCL 的脚本编程工具语言, 方便学习, 功能强大.
2) 为什么要使用 Expect
在现今的企业运维中, 自动化运维已经成为运维的主流趋势, 但是在很多情况下, 执行系统命令或程序时, 系统会以交互式的形式要求运维人员输入指定的字符串, 之后才能继续执行命令. 例如, 为用户设置密码时, 一般情况下就需要手工输入 2 次密码.
[root@aliyun shuzu]# passwd ming66
Changing password for user ming66.
- New password:
- BAD PASSWORD: it is WAY too short
- BAD PASSWORD: is too simple
- Retype new password:
passwd: all authentication tokens updated successfully.
简单来说, Expect 就是用来自动实现与交互式程序通信的, 而无需管理员的手工干预. 比如 SSH,FTP 远程连接等, 正常情况下都需要手工与它们进行交互, 而使用 Expect 就可以模拟手工交互的过程, 实现自动与远端程序的交互, 从而达到自动化运维的目的.
以下是 Expect 的自动交互工作流程简单说明, 依次执行如下操作:
spawn 启动指定进程 -->expect 获取期待的关键字 -->send 向指定进程发送指定字符 --> 进程执行完毕, 退出结束
二: 安装 Expect 软件和简单实现交互功能
准备好两台实验虚拟机, IP 地址为 192.168.1.7 和 192.168.1.8 并设置好 yum 源, 安装 Expect 安装包
- [root@aliyun ~]# yum install expect -y
- [root@aliyun ~]# ifconfig |grep 'inet addr:'|awk -F "[ :]" '{print $13}'
- 192.168.1.7
- 127.0.0.1
- [root@aliyun ~]# ssh -p22 root@192.168.1.8
The authenticity of host '192.168.1.8 (192.168.1.8)' can't be established.
RSA key fingerprint is c8:f2:9e:53:55:98:37:10:31:8f:1a:62:9a:58:c7:8e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.8' (RSA) to the list of known hosts.
- root@192.168.1.8's password:
- Last login: Sat Jun 9 03:31:56 2018 from 192.168.1.11
- [root@aliyun ~]# ifconfig |grep 'inet addr:' |awk -F "[ :]" '{print $13}'
- 192.168.1.8
- 127.0.0.1
- [root@aliyun ~]# exit
- logout
Connection to 192.168.1.8 closed.
- [root@aliyun ~]# ssh -p22 root@192.168.1.8
- root@192.168.1.8's password:
- Last login: Sat Jun 9 03:37:29 2018 from 192.168.1.7
可以看到, 每次都需要手工输入密码, 才能执行 ssh 命令, 否则无法执行
下面就用 Expect 的功能实现自动交互, 发送密码并执行上诉 ssh 命令
- [root@aliyun ~]# cat ywxi.exp
- #!/usr/bin/expect #脚本开头解析器, 和 shell 类似, 表示程序使用 expect 解析
- spawn ssh root@192.168.1.8 uptime #执行 ssh 命令 (注意开头必须要有 spawn, 否则无法实现交互)
- expect "*password" #利用 expect 获取执行上述 ssh 命令输出的字符串是否为期待的字符串 *.password, 这里的 * 是通配符
- send "123456\n" #当获取到期待的字符串 * password 时, 则发送 123456 密码给系统,\n 为换行
- expect eof #处理完毕后结束 Expect
- # 执行 expect 脚本
- [root@aliyun ~]# which expect
- /usr/bin/expect
- [root@aliyun ~]# expect ywxi.exp
- spawn ssh root@192.168.1.8 uptime
- root@192.168.1.8's password:
03:46:18 up 16 min, 3 users, load average: 0.00, 0.02, 0.06
- [root@aliyun ~]# expect ywxi.exp
- spawn ssh root@192.168.1.8 uptime
- root@192.168.1.8's password:
03:46:30 up 16 min, 3 users, load average: 0.00, 0.02, 0.06
三: Expect 程序自动交互的重要命令及实践
Expect 程序中的命令是 Expect 的核心
1)spawn 命令
在 Expect 自动交互程序执行的过程中, spawn 命令是一开始就需要使用的命令, 通过 spawn 执行一个命令或程序, 之后所有的 Expect 操作都会在这个执行过的命令或程序进程中进行, 包括自动交互功能, 因此如果没有 spawn 命令, Expect 程序将无法实现自动交互. 所以使用 spawn 命令是 Expect 程序实现自动交互工作流程中的第一步, 也是最关键的一步
apawn 命令的语法为:
spawn [ 选项 ] [ 需要自动交互的命令或程序 ]
选项:
-open 表示启动文件进程
-ignore 表示忽略某些信号
例如:
spawn ssh root@192.168.1.8 uptime
2)expect 命令
expect 命令的作用就是获取 spawn 命令执行后的信息, 看看是否和其事先指定的相匹配, 一旦匹配上指定的内容就执行 expect 后面的动作, expect 命令也有一些选项, 相对用得较多的是 - re, 表示使用正则表达式的方式来匹配.
expect 命令的语法为:
expect 表达式 [ 动作 ]
例如:
- spawn ssh root@192.168.1.8 uptime
- expect "*password"
注: 上述命令不能直接在 linux 命令行中执行, 需要放入 expect 脚本中执行
expect 命令实践
范例 1: 执行 ssh 命令远程获取服务器负载值, 并要求实现自动输入密码
法 1: 将 expect 和 send 放在一行
- [root@aliyun ~]# cat ywxi.exp
- #!/usr/bin/expect
- spawn ssh root@192.168.1.8 uptime
- expect "*password" {send "123456\n"}
- expect eof
执行结果:
- [root@aliyun ~]# expect ywxi.exp
- spawn ssh root@192.168.1.8 uptime
- root@192.168.1.8's password:
04:06:30 up 36 min, 3 users, load average: 0.00, 0.00, 0.00
法 2: 将 expect 和 send 不放在一行
- [root@aliyun ~]# cat ywxi.exp
- #!/usr/bin/expect
- spawn ssh root@192.168.1.8 uptime
- expect "*password"
- send "123456\n"
- expect eof
执行结果:
- [root@aliyun ~]# expect ywxi.exp
- spawn ssh root@192.168.1.8 uptime
- root@192.168.1.8's password:
04:07:52 up 37 min, 3 users, load average: 0.00, 0.00, 0.00
范例 2: 利用 expect 响应 shell 脚本中的多个 read 读入
脚本前准备:
- [root@aliyun pratice]# cat readex.sh
- #!/bin/bash
- read -p 'please input your username:' name
- read -p 'please input your password:' pass
- read -p 'please input your email:' email
- echo -n "you name is $name,"
- echo -n "you password is $pass,"
- echo -n "you email is $email."
- [root@aliyun pratice]# sh readex.sh
please input your username:ywxi
please input your password:123456
please input your email:1031664140@qq.com
you name is ywxi,you password is 123456,you email is 1031664140@qq.com.
expect 脚本如下:
- [root@aliyun pratice]# cat expe.exp
- #/usr/bin/expect
- spawn /bin/sh readex.sh #这里在一个目录下, 用的相对路径
- expect {
- "username" {exp_send "ywxi\r";exp_continue} #若获取到的是 username 信息, 则自动输入 ywxi
- "*pass*" {send "123456\r";exp_continue} #若获取到的是 * pass * 信息, 则自动输入 123456
- "*mail*" {exp_send "1031664140@qq.com\r"} #若获取到的是 * mail * 信息, 则自动输入邮件地址
- }
- expect eof
执行结果如下:
- [root@aliyun pratice]# expect expe.exp
- spawn /bin/sh readex.sh
please input your username:ywxi
please input your password:123456
please input your email:1031664140@qq.com
you name is ywxi,you password is 123456,you email is 1031664140@qq.com.
3)send 命令
exp_send 和 send 命令的使用方法, 这两个命令是 expect 中的动作命令, 用法类似, 即在 expect 命令匹配指定的字符串后, 发送指定的字符串给系统, 这些命令可以支持一些特殊转义符号, 例如: \r 表示回车,\n 表示换行,\t 表示制表符等.
send 命令有几个可用的参数, 具体如下:
-i : 指定 spawn_id, 用来向不同的 spawn_id 进程发送命令, 是进行多程序控制的参数
-s: s 代表 slowly, 即控制发送的速度, 使用的时候要与 expect 中的变量 send_slow 相关联
4)exp_continue 命令
这个命令一般处于 expect 命令中, 属于一种动作命令, 一般用在匹配多次字符串的动作中, 从命令的拼写就可以看出命令的作用, 即让 Expect 程序继续匹配的意思.
使用示例如下:
- [root@aliyun pratice]# cat expe.exp
- #/usr/bin/expect
- spawn /bin/sh readex.sh
- expect {
- "username" {exp_send "ywxi\r";exp_continue}
- "*pass*" {exp_send "123456\r";exp_continue}
- "*mail*" {exp_send "1031664140@qq.com\r"}
- }
- expect eof
5)send_user 命令
send_user 命令可用来打印 Expect 脚本信息, 类似 shell 里的 echo 命令, 而默认的 send,exp_send 命令都是将字符串输出到 Expect 程序中去.
示例如下:
- [root@aliyun pratice]# cat send.exp
- #!/usr/bin/expect
- send_user "I am ywxi.\n" #\n 表示换行
- send_user "I am linuxer,\t" #\t 表示 Tab 键
- [root@aliyun pratice]# expect send.exp
I am ywxi.
I am linuxer, [root@aliyun pratice]
四: Expect 程序变量介绍
1) 普通变量
Expect 中的变量定义, 使用方法与 TCL 语言中的变量基本相同
定义变量的基本语法如下:
set 变量名 变量值
示例如下:
set password "123456"
打印变量的基本语法如下:
puts $ 变量名
范例: 定义及输出变量
- [root@aliyun pratice]# cat bl.exp
- #!/usr/bin/expect
- set password "123456"
- puts $password
- send_user "$password\n" #send_user 也可以打印输出
- [root@aliyun pratice]# expect bl.exp
- 123456
- 123456
2) 特殊参数变量
在 expect 里也有与 shell 脚本里的 $0,$1,$# 等类似的特殊参数变量, 用于接收及控制 Expect 脚本传参.
来源: http://www.bubuko.com/infodetail-2637113.html