真锋
永远保持一颗学习和专注的心
嵌入式视觉笔记

expect 实现脚本的自动交互

expect 介绍

这篇文章大部分参考这里,expect 的用户网上靠谱的文章实在太少了,导致我没法同时学习多个文章好加以总结,毕竟一家之言还是有所偏驳。

expect 是建立在 tcl 语言基础上的一个自动化交互套件, 在一些需要交互输入指令的场景下, 可通过脚本设置自动进行交互通信。可以将交互过程如:ssh 登录、ftp 登录、scp 复制文件等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率。其交互流程是:
spawn 启动指定进程 -> expect 获取指定关键字 -> send 想指定进程发送指定指令 -> 执行完成, 退出。

安装 expect

使用以下代码检测 expect 是否已经安装

 ls /usr/bin | grep expect 

如果显示为空,则使用以下命令安装

sudo apt-get install tcl tk expect

expect 命令学习

expect 是基于 tcl 演变而来的,所以很多语法和 tcl 类似,基本的语法如下所示:

# 首行加上 /usr/bin/expect
# spawn:后面加上需要执行的 shell 命令,比如说 spawn sudo touch testfile;
# expect:只有 spawn 执行的命令结果才会被 expect 捕捉到,因为 spawn 会启动一个进程,只有这个进程的相关信息才会被捕捉到,主要包括:标准输入的提示信息,eof 和 timeout。
# send 和 send_user:send 会将 expect 脚本中需要的信息发送给 spawn 启动的那个进程,而 send_user 只是回显用户发出的信息,类似于 shell 中的 echo 而已。

expect 实际的作用就是监听目标进程的输出(spawn),根据期望输出(expect),进行响应 (send)。学习 expect 工具,实际上学习三个核心指令 spawnexpectsend的使用,这三个指令的具体语法理解见下文。

spawn

spawn [args] program [args]

用以创建新的进程,并执行给定的程序,后面就可以使用 expect 监听 spawn 创建进程程序的输出。

expect

expect 常用语法(模式-动作)如下:

expect [[-opts] pattern body1] ... [-opts] pattern [bodyn]

expect 的参数是一连串的 opts,pattern,body,也就是 expect 可用来监听多个输出,pattern 就是用来匹配期望的输出,一旦匹配上就执行后面的 bodyopts 表示可选。用法示例如下:

expect {
      busy {puts busy\n}
      -re "failed|invalid password" {puts failed]\n}  # -re选项表示开启正则匹配
      timeout {puts timeout\n}
      connected
  }

注意,expect 会等待目标进程的输出,然后进行匹配,这个等待的时间默认是10秒,一旦超过这个时间就直接执行下一条指令,我们可以通过设置 timeout 来更改这个时间,set timeout 100 表示等待 100 秒。

send

send [-flags] string

将字符串传递给当前进程,这里就是模拟人的输入。

expect eof

expect eof 用以防止 spawn 进程程序执行完就直接退出的情况,有了它,程序会等待 spawn 进程程序结束再退出。由 spawn 启动的程序在结束的时候会产生一个 eof 标示,expect eof 会等待 spawn 进程程序的退出 eof 标示,一旦匹配到 eof 标识就什么也不做,什么也不做,没什么可做也就退出了。
但是,expect 是有默认超时时间的 -10 秒, 如果程序执行时间超过10 秒或更久,显然 expect eof 会超时,程序会直接退出,解决办法就是设置 timeout。对于远程文件备份这种耗时比较长的操作,我们就需要设置 expect 的超时时间。

expect 实例

自动拷贝 scp

scp 远程复制文件(夹)涉及到很多交互式命令,我们不得不人工响应,expect 的出现解决了这个问题,实例脚本如下。

spawn scp -r $Dataset_path ftpdata@47.104.23.88:/mnt/data-4/ftpdata/honggao.zhang/
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "$password\n" }
}
expect eof

Shell 脚本实现了 scp 复制本地目录到远程服务器,无需我们手动密码,同理 ssh 登录也可类似操作。建议把自动拷贝 scp 功能封装成函数形式,否则你得先 chmod a+x xxx.sh 然后 ./xxx.sh 才能执行脚本成功,下面的自动登录 ssh 实例代码就是封装成函数的形式。

自动登录 ssh

# ssh waibao server
# wait for upload success
echo "start ssh waibao server"
sshdzd(){
expect <<-EOF
set timeout 1000
spawn ssh $user_name@$server_ip
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "$password\n" }
}
expect eof
EOF
}
sshdzd

脚本运行成功输出如下:

start ssh waibao server
spawn ssh ftpdata@47.104.23.88
ftpdata@47.104.23.88’s password:
Last login: Tue Jul 2 21:00:02 2019 from 221.226.80.68
Welcome to Alibaba Cloud Elastic Compute Service !

参考资料

expect自动交互详解
Ubuntu使用Spawn和expect实现ssh自动登陆
Linux中通过expect工具实现脚本的自动交互

赞赏

发表评论

textsms
account_circle
email

嵌入式视觉笔记

expect 实现脚本的自动交互
expect 介绍 这篇文章大部分参考这里,expect 的用户网上靠谱的文章实在太少了,导致我没法同时学习多个文章好加以总结,毕竟一家之言还是有所偏驳。 expect 是建立在 tcl 语言基础…
扫描二维码继续阅读
2019-07-03