expect实现非交互
一、exepct介绍
expect命令是一个实现交互功能的软件套件,是基于TCL的脚本编程语言,在企业运维中,系统会以交互的形式要求运维人员输入指定的字符串,之后才能继续执行命令。例如:为用户设置密码时,一般情况下需要手工输入两次密码,比如使用ssh连接远程服务器时,第一次连和系统实现两次交互。
简单的说,expect用来自动实现与交互程序通信的,无需管理员手工干预
spawn启动指定进程>expect获取期待的关键字>send向指定进程发送字符>进程执行完毕,退出
二、expect程序自动交互
expect程序中的命令是expect的核心
spawn [选项] [需要交互的命令或程序]
例如:
spawn ssh root@192.168.4.5 uptime
在spawn命令的后面,直接要加上要执行的命令或程序
expect命令语法
在expect自动交互的执行过程中,当使用spawn命令执行一个命令或程序之后,会提示某些交互信息,expect命令的作用就是获取spawn命令执行的信息,看看是否有事先指定的相匹配,一旦匹配上指定的内容就执行expect后面的动作。
expect 表达式 [动作]
例如:
spawn ssh root@192.168.4.5 uptime
expect “*password” {send “666666\r”}
send 发送字符串
当然,他也可以在一个expect匹配中多次匹配不同的字符串,并给出不同的处理动作,此时,只需要将匹配的所有字符串放在一个{}大括号中就可以了,好需要借助exp_continue指令实现继续匹配。
2.1 实现自动交互
#!/usr/bin/expect
spawn ssh root@192.168.4.5 uptime
expect {
"yes/no" {exp_send "yes\r";exp_continue}
"*password" {exp_send "666666\r"}
}
expect eof
expect_send和send类似,\r 回车
expect{},类似多行expect。
exp_continue 匹配多个字符串,需要在每次匹配并执行动作后继续匹配,加上exp_continue
exp_eof 想要输出结果,必须加eof,表示expect结束
2.2利用expect响应shell脚本中的多个read读入
[root@localhost ~]# vim xinxi.sh
#!/bin/bash
read -p "pls input your username:" name
read -p "pls input your password:" pass
read -p "pls input your email:" mail
echo -n "your name is $name ,"
echo -n "your passwordis $pass ,"
echo "your emali is $mail"
[root@localhost ~]# sh xinxi.sh
pls input your username:calabash
pls input your password:666666
pls input your email:calabash@163.com
your name is calabash ,your passwordis 666666 ,your emali is calabash@163.com
用expect自动化脚本,实现自动输入多个字符串
[root@localhost ~]# vim expxinxi.exp
#!/usr/bin/expect
spawn /bin/sh xinxi.sh
expect {
"username" {exp_send "calabash\r";exp_continue}
"password" {send "666666\r";exp_continue}
"email" {exp_send "calabash@163.com\r"}
}
expect eof
执行,全部自动输入,实现了自动化
[root@localhost ~]# expect expxinxi.exp
spawn /bin/sh xinxi.sh
pls input your username:calabash
pls input your password:666666
pls input your email:calabash@163.com
your name is calabash ,your passwordis 666666 ,your emali is calabash@163.com
send_user 可以用来打印expect脚本的信息,类似shell里的echo命令
[root@localhost ~]# vim me.exp
#!/usr/bin/expect
send_user "I am calabash. \n"
send_user "I am a linuxer. \t"
send_user "mysql email is calabash@163.com\n"
[root@localhost ~]# expect me.exp
I am calabash.
I am a linuxer. mysql email is calabash@163.com
\n 换行
\t tab键
exit命令类似于shell脚本的exit,即直接退出expect脚本,除了最基本的退出,还可以利用exit做一些提示
例如:
[root@localhost ~]# vim me.exp
#!/usr/bin/expect
send_user "I am calabash. \n"
send_user "I am a linuxer. \t"
send_user "mysql email is calabash@163.com\n"
exit -onexit {
send_user "Good bye.\n"
}
[root@localhost ~]# expect me.exp
I am calabash.
I am a linuxer. mysql email is calabash@163.com
Good bye.
2.3 常用命令总结
spawn:用过spawn执行一个程序或命令,之后所有的expect操作都在这个执行的程序或命令中执行。
expect:获取spawn程序的交互信息,查看是否和其事先指定的信息想匹配。
send:当expect匹配了指定的字符串后,发送指定的字符串给系统,这些命令可以支持一些特殊的转义符号,例如: \r回车 \n换行 \t tab等
exp_contine:继续匹配expect程序或命令
send_user:打印脚本信息
exit:退出expect脚本,也可以做清理或提示工作
三、expect程序变量
3.1普通变量
定义变量:
set 变量名 变量值
打印变量:
puts $变量名
示例:
[root@localhost ~]# vim shili.exp
#!/usr/bin/expect
set password "666666"
puts $password
send_user "$password\n"
[root@localhost ~]# expect shili.exp
666666
666666
3.2 特殊参数变量
在expect里也有与shell脚本里的$0 $1 $2 等类似的特殊参数变量,用于接收控制expect脚本传参
在expect中$argv表示参数数组,可以使用[lindex $argv n]接收expet脚本传参,n从0开始,分别表示第一个[lindex $argv 0]参数、第二个[lindex $argv 1]、第三个[lindex $argv 2参数]
例如:
[root@localhost ~]# vim shili.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\n"
puts $argc
puts $argv0
加三个位置参数
[root@localhost ~]# expect shili.exp a.txt 192.168.4.5 /root
a.txt 192.168.4.5 /root
3
shili.exp
$argc 表示传参的个数
$argv0 表示脚本本身的名字
3.3 关键字变量
timeout是一个控制时间的关键字变量,是一个全局性时间的控制开关,可以通过为这个变量赋值来规定整个expect操作的时间。因为作用于全局,即使命令没有错误,到了时间仍然会激活这个变量,此外,到时间后还会激活一个处理及提示信息开关。
示例:
此脚本测试超时返回值,所以不设置密码,5秒后超时返回
[root@localhost ~]# vim shili.exp
#!/usr/bin/expect
spawn ssh roo@192.168.4.5 uptime
set timeout 5
expect "yes/no" {exp_send "yes\r;exp_continue"}
expect timeout {puts "Request timeout by calabash.";return}
[root@localhost ~]# expect shili.exp
spawn ssh roo@192.168.4.5 uptime
roo@192.168.4.5's password: Request timeout by calabash.
此外,在expect{}用法,还可以这样使用timeout
[root@localhost ~]# vim shili.exp
#!/usr/bin/expect
spawn ssh roo@192.168.4.5 uptime
expect {
-timeout 3
"yes/no" {exp_send "yes\r";exp_continue}
timeout {puts "Request timeout by calabash.";return}
}
[root@localhost ~]# expect shili.exp
spawn ssh roo@192.168.4.5 uptime
roo@192.168.4.5's password: Request timeout by calabash.
四、expect程序中的if条件语句
4.1 if语句的语法
if { 条件表达式 } {
指令
}
或者
if { 条件表达式 } {
指令
} else {
指令
}
注意:if关键字后面要有空格,else关键字前后要有空格
{条件表达式} 大括号里可以没有空格, 外面前后要有空格
4.2 if判断示例
使用if语句判断脚本传参的个数,不管是否符合都给予提示
[root@localhost ~]# vim shili.exp
#!/usr/bin/expect
if { $argc != 26 } {
puts "bad."
} else {
puts "good."
}
[root@localhost ~]# expect shili.exp
bad.
[root@localhost ~]# expect shili.exp {a..z}
good.
五、expect生产环境案例
5.1 实现自动交互的脚本
[root@G ~]# vim zd.exp
#!/usr/bin/expect
if { $argc != 2 } {
puts "usage: expect $argv0 ip command"
exit
}
#
set ip [lindex $argv 0]
set cmd [lindex $argv 1]
set password "666666"
#
spawn ssh root@$ip $cmd
expect {
"yes/no" {send "yes\r";exp_continue} &> /dev/null
"*password" {send "$password\r"} &> /dev/null
}
expect eof
脚本后加上ip和命令
[root@G ~]# expect zd.exp 192.168.4.5 uptime
spawn ssh root@192.168.4.5 uptime
root@192.168.4.5's password:
05:15:09 up 15 min, 2 users, load average: 0.00, 0.00, 0.00
5.2 利用for循环查看多台
现有2台服务器,需要用管理机去查看
Ip地址 |
主机名 |
角色 |
192.168.4.4 |
G |
管理机 |
192.168.4.5 |
b1 |
被管理机 |
192.168.4.6 |
b2 |
被管理机 |
[root@G ~]# vim pl.sh
#!/bin/bash
if [ $# -ne 1 ];then
echo $"USAGE:$0 cmd"
exit 1
fi
cmd=$1
for n in 5 6
do
expect zd.exp 192.168.4.$n "$cmd"
done
[root@G ~]# sh pl.sh uptime
spawn ssh root@192.168.4.5 uptime
root@192.168.4.5's password:
01:00:21 up 36 min, 2 users, load average: 0.00, 0.00, 0.00
spawn ssh root@192.168.4.6 uptime
root@192.168.4.6's password:
01:00:21 up 35 min, 2 users, load average: 0.00, 0.00, 0.00
5.3 免交互发送文件
[root@G ~]# vim scpfile.exp
#!/usr/bin/expect
if { $argc != 3 } {
puts "usage: expect $argv0 file host dir"
exit
}
#
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "666666"
spawn scp -rp -P22 $file root@$host:$dir
expect {
"yes/no" {send "yes/r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
发送文件
[root@G ~]# expect scpfile.exp abc 192.168.4.6 /root/
spawn scp -rp -P22 abc root@192.168.4.6:/root/
root@192.168.4.6's password:
查看发送结果
[root@G ~]# expect zd.exp 192.168.4.6 ls
spawn ssh root@192.168.4.6 ls
root@192.168.4.6's password:
abc
anaconda-ks.cfg
install.log
install.log.syslog
5.4 利用shell循环批量发送文件
[root@G ~]# vim scpfile.sh
#!/bin/bash
if [ $# -ne 2 ];then
echo $"USAGE:$0 file dir"
exit 1
fi
#
file=$1
dir=$2
for n in 5 6
do
expect scpfile.exp $file 192.168.4.$n $dir
done
[root@G ~]# sh scpfile.sh wangluyu /root/
spawn scp -rp -P22 wangluyu root@192.168.4.5:/root/
root@192.168.4.5's password:
spawn scp -rp -P22 wangluyu root@192.168.4.6:/root/
root@192.168.4.6's password: