expect快速入门

expect简介

expect是一个自动化交互式应用程序的工具,所以expect可以用来处理交互的命令。借助expect,我们可以将交互过程写在一个脚本上,使之自动化完成。形象的说,ssh登录,ftp登录等都符合交互的定义。expect含有利用正则表达式进行模式匹配以及通用的编程功能,允许简单的脚本智能地管理如下工具:telnet,ftp和ssh(这些工具都缺少编程的功能),宏以及其它程序。expect脚本的出现使得这些老的软件工具有了新的功能和更多的灵活性。


expect脚本远程登录

以上简介中也提到了expect和shell类似,可以进行编程,接下来就实际的编写一些expect脚本来学习expect简单的使用方式。

如果你的系统没有安装expect,需要先安装expect,安装命令如下:

yum install -y expect

expect示例:编写一个自动远程登录脚本,expect编写的脚本文件后缀名为expect,这是为了好区分:

[root@localhost ~]# mkdir expectFiles
[root@localhost ~]# cd expectFiles/
[root@localhost ~/expectFiles]# vim telnet_ept.expect
#! /usr/bin/expect
# 需要登录的IP
set host "192.168.77.128"
# 密码
set passwd "123456"
# 登录的命令
spawn ssh root@$host
# expect用于执行一些命令
expect {
# 初次登录会询问"yes/no",所以如果截取的是"yes/no"就 send 发送一个yes,\r是回车的意思,exp_continue表示继续
"yes/no" { send "yes\r"; exp_continue}
# 如果截取的是"password:"就 send 发送密码
"password:" { send "$passwd\r" }
}
# 结束标识,但是不会退出登录,不加interact的话就会马上退出登录
interact
  • Tips:expect语法中不允许行尾注释,注释需要另起一行,否则会报错

set是用来定义一个变量的,变量名后面跟的就是变量的值,不需要使用等于号来赋值,调用变量的方式和shell一样,也是使用$符号。

与interact相对的就是expect eof ,expect eof会在登录后,停留登录状态1-2秒后才退出登录。

执行这个脚本需要加一个执行权限,然后直接执行就可以了:

[root@localhost ~/expectFiles]# chmod a+x telnet_ept.expect 
[root@localhost ~/expectFiles]# ./telnet_ept.expect 
spawn ssh root@192.168.77.128
The authenticity of host '192.168.77.128 (192.168.77.128)' can't be established.
ECDSA key fingerprint is 4d:5a:9d:31:65:75:30:47:a3:9c:f5:56:63:c4:0f:6a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.77.128' (ECDSA) to the list of known hosts.
root@192.168.77.128's password: 
Last login: Wed Nov 29 14:07:45 2017 from 192.168.77.1
[root@localhost ~]#

运行结果如上,成功登录了192.168.77.128。


expect脚本远程执行命令

除了能够实现远程登录外,还能实现远程执行命令,例如可以写一个自动远程登录后,执行命令并退出的脚本:

[root@localhost ~/expectFiles]# vim telnet_2.expect
#!/usr/bin/expect
set user "root"
set passwd "123456"
spawn ssh $user@192.168.77.128

expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "$passwd\r" }
}
# 当遇到 "]#" 就执行send命令,我们登录后不就是:[root@localhost ~]#,末尾就是 ]# ,而send是发送touch创建文件的命令
expect "]#"
send "touch /tmp/12.txt\r"
# 同样的当遇到 "]#" 就执行send里的命令
expect "]#"
send "echo 1212 > /tmp/12.txt\r"
# 最后退出系统
expect "]#"
send "exit\r"

运行脚本:

[root@localhost ~/expectFiles]# chmod a+x telnet_2.expect 
[root@localhost ~/expectFiles]# ./telnet_2.expect
spawn ssh root@192.168.77.128
root@192.168.77.128's password: 
Last login: Wed Nov 29 14:54:34 2017 from 192.168.77.130
[root@localhost ~]# touch /tmp/12.txt
[root@localhost ~]# echo 1212 > /tmp/12.txt
[root@localhost ~]# 
[root@localhost ~/expectFiles]#

然后再来看看192.168.77.128机器上有没有/tmp/12.txt 文件:

[root@localhost ~]# ll /tmp/12.txt 
-rw-r--r-- 1 root root 5 11月 29 15:10 /tmp/12.txt
[root@localhost ~]# cat !$
cat /tmp/12.txt
1212
[root@localhost ~]# 

可以看到文件和内容与脚本中执行的命令一致。


expect脚本传递参数

expect脚本也是可以像shell脚本一样传递参数的,以下例子演示如何拿到脚本的参数:

[root@localhost ~/expectFiles]# vim telnet_3.expect
#!/usr/bin/expect
# expect脚本拿参数的方式有点像是在数组中拿元素一样,也是从0开始数,$argv是expect的一个内置变量
# 第一个参数,下标从0开始
set user [lindex $argv 0]
# 第二个参数
set host [lindex $argv 1]
set passwd "123456"
# 需要远程执行的命令
set cm [lindex $argv 2]
spawn ssh $user@$host

expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
# 执行命令然后退出登录
expect "]#"
send "$cm\r"
expect "]#"
send "exit\r"

以上脚本运行结果:

[root@localhost ~/expectFiles]# ./telnet_3.expect root 192.168.77.128 ls
spawn ssh root@192.168.77.128
root@192.168.77.128's password: 
Last login: Wed Nov 29 15:10:48 2017 from 192.168.77.130
[root@localhost ~]# ls
\                                           stop.sh     zabbix-release-3.2-1.el7.noarch.rpm
anaconda-ks.cfg                             Test.class
mysql57-community-release-el7-8.noarch.rpm  Test.java
[root@localhost ~]# 
[root@localhost ~/expectFiles]#

执行多条命令,使用引号将命令括起来即可:

[root@localhost ~/expectFiles]# ./telnet_3.expect root 192.168.77.128 "ls;w;who"
spawn ssh root@192.168.77.128
root@192.168.77.128's password: 
Last login: Wed Nov 29 15:29:30 2017 from 192.168.77.130
[root@localhost ~]# ls;w;who
\                                           stop.sh     zabbix-release-3.2-1.el7.noarch.rpm
anaconda-ks.cfg                             Test.class
mysql57-community-release-el7-8.noarch.rpm  Test.java
 15:29:48 up  5:13,  2 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.77.1     14:07   15:00   0.06s  0.06s -bash
root     pts/1    192.168.77.130   15:29    0.00s  0.02s  0.00s w
root     pts/0        2017-11-29 14:07 (192.168.77.1)
root     pts/1        2017-11-29 15:29 (192.168.77.130)
[root@localhost ~]# [root@localhost ~/expectFiles]#

关于这种远程执行命令的操作,会存在一个超时时间,也就是说,如果你需要远程执行的那条命令的执行时间,超过了默认的超时时间,命令的执行就会被终止。这个默认的超时时间是10秒,我们可以通过执行一条vmstat命令来测试出这个默认的超时时间:

[root@localhost ~/expectFiles]# ./telnet_3.expect root 192.168.77.128 "vmstat 1"
spawn ssh root@192.168.77.128
root@192.168.77.128's password: 
Last login: Wed Nov 29 17:25:48 2017 from 192.168.77.130
[root@localhost ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 3271556   1376 259272    0    0     4     1   35   64  0  0 100  0  0
 0  0      0 3271712   1376 259364    0    0     0     0   92  157  0  0 100  0  0
 0  0      0 3271712   1376 259364    0    0     0     0   76  128  0  0 100  0  0
 0  0      0 3271744   1376 259364    0    0     0     0   91  146  0  1 100  0  0
 0  0      0 3271744   1376 259364    0    0     0     0   64  120  0  0 100  0  0
 0  0      0 3271712   1376 259364    0    0     0     0   78  127  0  0 100  0  0
 0  0      0 3271712   1376 259364    0    0     0     0   57  104  0  0 100  0  0
 0  0      0 3271712   1376 259364    0    0     0     0   81  128  0  1 100  0  0
 0  0      0 3271712   1376 259364    0    0     0     0   75  127  0  0 100  0  0
 0  0      0 3271200   1376 259400    0    0     0     0   91  153  0  1 100  0  0
 0  0      0 3270936   1376 259400    0    0     0     0   92  152  0  0 100  0  0
[root@localhost ~/expectFiles]#

以上运行结果可以看到vmstat设置的间隔时间为1秒,只打印了11行数据就退出登录了,第一行打印不算在超时时间内,从第二行开始数,刚好是10行,每行打印的间隔时间是1秒,所以就可以知道默认的超时时间是10秒。

那么要如何修改这个默认的超时时间呢?只需要在脚本中加上一句set timeout即可,设置的时间单位为秒,示例:

#!/usr/bin/expect
set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "Zero-One1."
set cm [lindex $argv 2]
spawn ssh $user@$host
# 设置超时时间为3秒
set timeout 3

expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect "]#"
send "$cm\r"
expect "]#"
send "exit\r"

运行结果:

[root@localhost ~/expectFiles]# ./telnet_3.expect root 192.168.77.128 "vmstat 1"
spawn ssh root@192.168.77.128
root@192.168.77.128's password: 
Last login: Wed Nov 29 17:25:54 2017 from 192.168.77.130
[root@localhost ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 3271172   1376 259420    0    0     4     1   35   64  0  0 100  0  0
 0  0      0 3270968   1376 259508    0    0     0     0  104  174  0  0 100  0  0
 0  0      0 3270936   1376 259560    0    0     0     0   90  152  0  1 100  0  0
 0  0      0 3270780   1376 259596    0    0     0     0   83  137  0  0 100  0  0
[root@localhost ~/expectFiles]#

提示:如果你将set timeout的值设置为-1的话,就表示没有超时时间,命令会一直执行。


expect脚本同步文件

expect结合rsync 可以实现自动同步文件,代码示例:

[root@localhost ~/expectFiles]# vim synFile.expect
#!/usr/bin/expect
set passwd "123456"
spawn rsync -av root@192.168.77.128:/tmp/12.txt /tmp/

expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}
expect eof

以上脚本运行结果:

[root@localhost ~/expectFiles]# chmod a+x synFile.expect
[root@localhost ~/expectFiles]# ./synFile.expect 
spawn rsync -av root@192.168.77.128:/tmp/12.txt /tmp/
root@192.168.77.128's password: 
receiving incremental file list
12.txt

sent 30 bytes  received 84 bytes  228.00 bytes/sec
total size is 5  speedup is 0.04
[root@localhost ~/expectFiles]# cat /tmp/12.txt 
1212
[root@localhost ~/expectFiles]#

如果把脚本中的expect eof命令给注释掉,看看会发生什么:

[root@localhost ~/expectFiles]# ./synFile.expect 
spawn rsync -av root@192.168.77.128:/tmp/12.txt /tmp/
root@192.168.77.128's password: 
[root@localhost ~/expectFiles]#

从结果可以看到,还没来得及执行rsync命令就退出来了,所以在这种登录后需要执行命令的expect脚本中一定要加上expect eof或者interact,不然你需要远程执行的命令就会来不及被执行,这就是加不加expect eof或者interact的区别。

可能有些人会想到使用set timeout来设置一个超时时间避免马上退出登录,实际上是无效的,避免这种马上退出登录的方式只能用expect eof或者interact。


expect脚本指定host和要同步的文件

想要指定host和要同步的文件就把它们作为参数就好了:

#!/usr/bin/expect
set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -av $file root@$host:$file

expect {
"yes/no" { send "yes\r"}
"password:" { send "$passwd\r" }
}

expect eof

运行结果:

[root@localhost ~/expectFiles]# chmod a+x hostFile.expect 
[root@localhost ~/expectFiles]# ./hostFile.expect 192.168.77.128 "/tmp/12.txt"
spawn rsync -av /tmp/12.txt root@192.168.77.128:/tmp/12.txt
root@192.168.77.128's password: 
sending incremental file list

sent 31 bytes  received 12 bytes  86.00 bytes/sec
total size is 5  speedup is 0.12
[root@localhost ~/expectFiles]#

文件的路径要写绝对路径,然后需要使用双引号引起来。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【小项目】使用shell和expect实现简易的文件分发系统

    所以分发系统就是用来完成以上这个需求的,分发系统需要完成的事情就是将需要上线的代码分发到这些线上服务器中。我们现在要做的就是实现这个分发系统,实现这个系统需要用...

    端碗吹水
  • 搭建一个高可用负载均衡的集群架构(第一部分)

    4 由于机器有限,尽可能地把三个站点放到同一台服务器上,然后做负载均衡集群,要求所有站点域名解析到一个ip上,也就是说只有一个出口ip

    端碗吹水
  • 初识Spark

    Spark是Apache的一个顶级项目,Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Spark是UC Berkeley AMP l...

    端碗吹水
  • 分布式作业 Elastic-Job 快速上手指南,从理论到实战一文搞定!

    Java技术栈
  • 【自动化测试】【Jest-Selenium】(02)—— Jest 匹配器

    Use .toBe to compare primitive values or to check referential identity of object...

    WEBJ2EE
  • expect脚本中设置超时,比如下面的脚本

    文件expect_ssh_scp.sh #!/usr/bin/expect                                    ...

    拓荒者
  • [效率编程] 几个 Shell小工具( Expect Htop Ccat Z Iotop)

    最终实现了,高效的登录至服务器,不用输入密码.以及使用ccat查看源码,使用htop观察机器内存等信息.

    呼延十
  • 【CPP】各种各样的树(5)——AVL树

    之前说到在不断地随机插入删除后,二叉树会逐渐变得偏向一边,也就是逐渐右沉,这样的状态会严重地影响二叉树的查找效率。于是乎,我们希望可以构造出一种查找二叉...

    ZifengHuang
  • 4天上线“战疫”小程序,腾讯敏捷在数字广东的落地实践

    本文整理自数字广东“粤省事”高级产品经理黄伟斌在TOP100上的主题分享。 ? 项目缘起 数字广东公司于2017年10月成立,是由腾讯以及三大运营商共同组建的...

    TAPD敏捷研发
  • PHP童鞋改JAVA代码怎么处理

    静儿

扫码关注云+社区

领取腾讯云代金券