Contents
这篇文章大部分参考这里,expect 的用户网上靠谱的文章实在太少了,导致我没法同时学习多个文章好加以总结,毕竟一家之言还是有所偏驳。
expect
是建立在 tcl
语言基础上的一个自动化交互套件, 在一些需要交互输入指令的场景下, 可通过脚本设置自动进行交互通信。可以将交互过程如:ssh
登录、ftp
登录、scp
复制文件等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率。其交互流程是:
spawn
启动指定进程 -> expect
获取指定关键字 -> send
想指定进程发送指定指令 -> 执行完成, 退出。
使用以下代码检测 expect
是否已经安装
ls /usr/bin | grep expect
如果显示为空,则使用以下命令安装
sudo apt-get install tcl tk 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
工具,实际上学习三个核心指令 spawn
、expect
、send
的使用,这三个指令的具体语法理解见下文。
spawn [args] program [args]
用以创建新的进程,并执行给定的程序,后面就可以使用 expect
监听 spawn
创建进程程序的输出。
expect
常用语法(模式-动作
)如下:
expect [[-opts] pattern body1] ... [-opts] pattern [bodyn]
expect
的参数是一连串的 opts,pattern,body
,也就是 expect 可用来监听多个输出,pattern
就是用来匹配期望的输出,一旦匹配上就执行后面的 body
,opts
表示可选。用法示例如下:
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 [-flags] string
将字符串传递给当前进程,这里就是模拟人的输入。
expect eof
用以防止 spawn
进程程序执行完就直接退出的情况,有了它,程序会等待 spawn
进程程序结束再退出。由 spawn
启动的程序在结束的时候会产生一个 eof
标示,expect eof
会等待 spawn
进程程序的退出 eof
标示,一旦匹配到 eof
标识就什么也不做,什么也不做,没什么可做也就退出了。
但是,expect 是有默认超时时间的 -10
秒, 如果程序执行时间超过10 秒或更久,显然 expect eof 会超时,程序会直接退出,解决办法就是设置 timeout
。对于远程文件备份这种耗时比较长的操作,我们就需要设置 expect 的超时时间。
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 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工具实现脚本的自动交互