使用 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 还有完备的流程控制等许多强大功能,不过简单使用的话了解超时设置,判断待执行程序输出,自动输入就够了。

expect(1) - Linux man page

Expect command and how to automate shell scripts like magic

Linux 利用 expect 进行 scp 自动同步文件


2020-03-20 16:50 +0800