Shell编程之expect免交互

Posted 纵拥千晚星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell编程之expect免交互相关的知识,希望对你有一定的参考价值。

交互技能展示:

  • 掌握 expect 基本命令的使用方法
  • 掌握 expect 的执行方式
  • 会编写 expect 脚本实现免交互

expect 概述

expect 是建立在 tcl 语言基础上的一个工具,它可以让一些需要交互的任务自动化地完成。相当于模拟了用户和命令行的交互操作。Expect 是用来进行自动化控制和测试的工具。主要解决 shell 脚本中不可交互的问题。对于大规模的 linux 运维很有帮助在 linux 运维和开发中,我们经常需要远程登录服务器进行操作,登录的过程是一个交互的过程,可能会需要输入 yes/no password 等信息。为了模拟这种输入,可以使用 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

以上是关于Shell编程之expect免交互的主要内容,如果未能解决你的问题,请参考以下文章

Shell编程之expect免交互

Shell编程之Expect免交互

Expect 自动化控制和测试 Here Document 免交互 Linux- shell编程之免交互

Shell编程——Expect免交互

Shell脚本之Expect免交互

Shll编程之Expect免交互