Shell编程之expect免交互

最是人间留不住,朱颜辞镜花辞树。这篇文章主要讲述Shell编程之expect免交互相关的知识,希望能为你提供帮助。
交互技能展示:

  • 掌握 expect 基本命令的使用方法
  • 掌握 expect 的执行方式
  • 会编写 expect 脚本实现免交互
expect 概述
expect 是建立在 tcl 语言基础上的一个工具,它可以让一些需要交互的任务自动化地完成。相当于模拟了用户和命令行的交互操作。Expect 是用来进行自动化控制和测试的工具。主要解决 shell 脚本中不可交互的问题。对于大规模的 linux 运维很有帮助在 linux 运维和开发中,我们经常需要远程登录服务器进行操作,登录的过程是一个交互的过程,可能会需要输入 yes/no password 等信息。为了模拟这种输入,可以使用 Expect脚本一个常用的场景就是批量配置集群无秘钥登录。如果集群的机器数量很多,手动一台一
【Shell编程之expect免交互】台地去每台机子去配置无密钥是非常糟糕的事情。使用 expect 功能,可以远程登录机器,并通过交互方式进行无秘钥登录。
5.2 Except 安装
Linux 系统自身并没有安装 expect 和 tcl,需要手动安装。CenOS7.3 光盘中默认涵盖except 安装包,所以需要先挂载光盘,制作本地 yum 仓库,然后通过 yum 安装 except,安装过程中,yum 会自动安装其依赖软件 tcl。具体安装步骤如下。
(1)挂载光盘
通过 mount 命令挂载光盘到本地的/media 目录
[root@localhost ~]# mount /dev/sr0 /media
(2)制作本地 YUM 源
进入/etc/yum.repos.d/目录,删除默认存在的所有仓库配置文件,新建文件,并命名为 local.repo,其中后缀.repo 是必须的。配置文件内容如下。
[root@master~]#vim /etc/yum.repos.d/local.repo
name=localrepo
baseurl=file:///media
gpgcheck=0
编写完配置文件后,执行以下命令删除 yum 缓存,并更新。
[root@master~]#yum clean all
[root@master~]#yum make cache
(3)执行安装命令
执行以下命令,通过 yum 安装 except 软件。
[root@master~]#yum install -y expect
安装完之后,可以通过 rpm -qa 检查一下:
[root@master~]# rpm -qa|grep expect
expect-5.45-14.el7_1.x86_64
[root@master~]# rpm -qa|greptcl
tcl-8.5.13-8.el7.x86_64
基本命令介绍
1.脚本解释器
expect 脚本中首先引入文件,表明使用的是哪一个 shell。
#!/usr/bin/expect
2.expect/send
expect 的一个内部命令,判断上次输出结果里是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回,只能捕捉由 spawn 启动的进程的输出。
expect 接收命令执行后的输出,然后和期望字符串匹配,若对应这执行相应的 send向进程发送字符串,用于模拟用户的输入,该命令不能自动回车换行,一般要加\\r(回车)
其常见语法形式有以下三种,分别是。
(1)方式一
expect "$case1" send "$respond1\\r"
(2)方式二
expect "$case1"
send "$response1\\r"
(3)方式三
expect 可以有多个分支,就像 switch 语句一样。
expect

"$case1" send "$response1\\r"
"$case2" send "$response2\\r"
"$case3" send "$response3\\r"

其中$case1 代表检测命令的输出结果,如果输出内容和$case1 一致,通过 send 命令模
拟用户发送内容到终端。
  1. spawn
spawn 后面通常跟一个命令,表示开启一个会话、启动进程,并跟踪后续交互信息。
其语法为:
spawn Linux 执行命令
如跟踪切换用户的交互信息,可以执行以下命令。
spawn su root
4.结束符
expect eof :等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了
interact : 执行完成后保持交互状态, 把控制权交给控制台,这时可以手动输入信息
注:expect eof 与 interact 二选一即可。
5.set
expect 默认的超时时间是 10 秒,通过 set 命令可以设置会话超时时间, 若不限制超时时间则应设置为-1,如执行以下命令将超时时间设置为 30 秒。
set timeout 30
6.exp_continue
允许 expect 继续向下执行指令
  1. send_user
回显命令,相当于 echo
8.接收参数
Expect脚本可以接受从 bash 传递的参数.可以使用[lindex $argv n]获得,n 从 0开始,分别表示第一个,第二个,第三个....参数
参数存在 argv 中,使用第一个参数如下:
set param0 [lindex $argv 0]
$argc 表示参数个数,判断语句如下:
if $argc< 1
#do something
send_user "usage: $argv0 < param1> < param2> ... "
exit

注:$argv0 是脚本名,但[lindex $argv 0]是第一个参数 param1, [lindex $argv 1]
是第二个参数 param2, 以此类推
send_user 用来显示信息到父进程(一般为用户的 shell)的标准输出。
5.4 Expect 语法
1.语法结构
(1)单一分支语法
单一分支用于简单的用户交互,当监控命令的标准输出满足 expect 指定的字符串时,
向标准输入发送 send 指定的字符串。用法如下。
expect "password:" send "mypassword\\r“;
默认情况下,send 不会向标准输入发送回车键,所以需要通过\\r 手动换行。
(2)多分支模式语法
多分支用于复杂的用户交互,一般情况下输出内容可能有多个,根据不同的输出内容,
分别向标准输入发送不同的内容。其语法格式如下。
expect

"aaa" send "AAA\\r"
"bbb" send "BBB\\r"
"ccc" send "CCC\\r"

只要匹配了 aaa 或 bbb 或 ccc 中的任何一个,执行相应的 send 语句后退出该 expect
语句
另外一种多分支结构如下。
expect

"aaa" send “AAA”; exp_continue
"bbb" send “BBB”; exp_continue
"ccc" send "CCC"

exp_continue 表示继续后面的匹配,如果匹配了 aaa,执行完 send 语句后还要继续向下匹配 bbb
  1. Expect 执行方式
(1)直接执行
[root@master~]#more a.sh
#!/usr/bin/expect //Expect 二进制文件的路径
set timeout 60
log_file test.log
log_user 1
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh root@$hostname
expect
"(yes/no)"
send "yes\\r"; exp_continue
"*password"
send "$password\\r"

Interact
[root@master~]#chmoda+x a.sh
[root@master ~]# ./a.sh
(2)嵌入执行
[root@master ~]# more b.sh
#!/bin/bash
hostname=$1
password=$2
/usr/bin/expect< < -EOF //Expect 开始标志
spawn ssh root@$hostname
expect
"(yes/no)"
send "yes\\r"; exp_continue
"*password"
send "$password\\r"

expect "*]#"
send "exit\\r"
expect eof
EOF //Expect 结束标志,EOF 前后不能有空格
[root@master ~]# source b.sh
5.5 Expect 案例
案例一:创建用户 tom,密码 tom123
  1. 案例分析
正常情况下的交互过程如下所示。
[root@master ~]# useradd tom
useradd: user tom already exists
[root@master ~]# useradd jack
[root@master ~]# passwd jack
Changing password for user jack.
New password:
BAD PASSWORD: The password is shorter than 8 characters
Retype new password:
passwd: all authentication tokens updated successfully.
  1. 案例实施
根据正常的交互过程,编写 expect 脚本如下。
#!/bin/bash
user=$1
password=$2
useradd $user
expect < < EOF
spawn passwd $user //开启一个进程跟踪 passwd 命令,expect 只能捕捉该进程信息
expect "New password:" //匹配输出信息"New password:"
send "$password\\r" //自动输入密码
expect "Retype new password:" //匹配输出信息"Retype new password:"
send "$password\\r" //自动输入密码
expect eof; //等待结束标记
EOF
案例二:实现 ssh 自动登录
  1. 案例分析
ssh 登录过程根据不同的场景会出现多种交互形式,比较典型的交互场景如下。
(1)首次登录
[root@master ~]# ssh 192.168.8.136
The authenticity of host 192.168.8.136 (192.168.8.136) cant be established.
ECDSA key fingerprint is 61:9c:8f:1f:aa:41:e4:48:16:18:cb:61:52:a7:dd:00.
Are you sure you want to continue connecting (yes/no)?
(2)正常登录
[root@master ~]# ssh 192.168.8.136
root@192.168.8.136s password:
(3)连接被拒绝,可能是 ssh 没开,或者端口不对,或者防火墙限制
[root@master ~]# ssh 192.168.8.136 -p 12345
ssh: connect to host 192.168.8.136 port 12345: Connection refused
(4)没有连接地址
[root@master ~]# sshabcd
ssh: Could not resolve hostname abcd: Name or service not known
2.案例实施
利用 Expect,根据不同的场景,编写脚本如下。
[root@master ~]# more a.sh
#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh $hostname
expect
"Connection refused" exit
"Name or service not known" exit
"to continue" send "yes\\r"; exp_continue
"password:" send "$password\\r"

interact
exit
[root@master ~]#./a.sh 192.168.8.136 abc123
spawn ssh 192.168.8.136
root@192.168.8.136s password:
Last login: Fri Apr 20 17:38:35 2018 from 192.168.8.134
案例三:利用 Expect 完成 FTP 登录过程
1.案例分析
正常的 FTP 登录交互过程如下。
[root@master ~]# ftp 192.168.8.136
Connected to 192.168.8.136 (192.168.8.136).
220 (vsFTPd 3.0.2)
Name (192.168.8.136:root): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd pub
250 Directory successfully changed.
ftp>
2.案例实施
编写 expect 脚本如下。
[root@master ~]# ftp 192.168.8.136
#!/usr/bin/expect -f
set timeout 10
spawn ftp 192.168.8.136
expect "Name*"
send "ftp\\r"
expect "Password:*"
send "\\r"
expect "ftp> *"
interact
expect eof

    推荐阅读