使用 expect 和 scp 分发文件给其他主机
由于要将一个 jar 包拷贝到集群的每个主机上,又要经常改改代码再测试。于是找到了使用 expect 模拟交互,使用 scp 将文件拷贝到一个列表中的所有主机上。
什么是 expect
expect - programmed dialogue with interactive programs, Version 5
expect 是一个可以编程的,和其他程序交互的程序。根据编写的脚本,expect 可以和其他程序交互,并且对响应作出反应。
什么时候使用 expect
在使用 passwd 为用户修改密码的时候,会要求我们输入密码,这个时候 passwd 会 hang 等待我们输入密码,对于在自动化的场景中,假设我们想预先设置这个值,有什么办法呢?
对于这种情况,passwd 提供了一个 –stdin 的选项,可以用管道符从标准输入提供一个密码,例:
echo myPassword | passwd myUser --stdin
但是有些命令没有提供这样的选项,我们可以使用 expect 来代替我们进行交互。
简单使用
expect 底层是基于 Tcl (Tool Command Line) 的,所以 expect 的语法与 Tcl 一致。
常用命令
-
spawn
运行一个脚本或者程序。
example:
spawn scp file user@host:path
-
expect
等待程序输出。
example:
expect "yes" # 表示等待输出包含 yes
-
send
给程序输入,类似手动输入数据.
example:
send "myPassword\r"
表示输入 myPassword 并模拟输入回车键。
-
interact
进入交互模式,将控制权交还给用户。
使用 expect 替我们输入 scp 的密码
#!/usr/bin/expect
# 预设变量
set timeout 3600
set host 192.168.1.2
set port 22
set username user
set password pass
set src_file /tmp/src.file
set dest_file /tmp/dest.file
# 执行 scp 命令
spawn scp -P ${port} ${src_file} ${username}@${host}:${dest_file}
expect {
# 接受密钥认证
"(yes/no)?" {
send "yes\r"
expect "*assord:" { send "${password}\r"}
}
# 输入密码
"*assword:" {
send "${password}\r"
}
}
# 等待传输完成
expect "100%"
expect eof
这样,我们可以使用这个脚本替我们自动将文件传递到目标主机。类似的,我们可以编写 shell 脚本,将指定文件发送给特定主机列表。
当然, expect 还有完备的流程控制等许多强大功能,不过简单使用的话了解超时设置,判断待执行程序输出,自动输入就够了。