使用 Linux 的朋友对输入密码都不会陌生, 比如使用超级用户执行命令, 又比如 scp,SSH 连接远程主机等等. 如果我们脚本里面有 scp 的操作, 总不可能执行一次 scp 就输入密码一次, 这样就需要一个人盯着脚本运行了. 为了解决这个问题, 我们需要一个自动输入密码的功能.
expect 是建立在 tcl 基础上的一个工具, 它可以让一些需要交互的任务自动化地完成. 相当于模拟了用户和命令行的交互操作.
一个具体的场景: 远程登陆服务器, 并执行命令.
expect 是什么?
expect 是一个免费的编程工具, 用来实现自动的交互式任务, 而无需人为干预. 说白了, expect 就是一套用来实现自动交互功能的软件.
在实际工作中, 我们运行命令, 脚本或程序时, 这些命令, 脚本或程序都需要从终端输入某些继续运行的指令, 而这些输入都需要人为的手工进行. 而利用 expect, 则可以根据程序的提示, 模拟标准输入提供给程序, 从而实现自动化交互执行. 这就是 expect!!!
expect 基础
在使用 expect 时, 基本上都是和以下四个命令打交道:
命令作用: send 用于向进程发送字符串, expect 从进程接收字符串, spawn 启动新的进程, interact 允许用户交互.
说明:
send 命令接收一个字符串参数, 并将该参数发送到进程.
expect 命令和 send 命令相反, expect 通常用来等待一个进程的反馈, 我们根据进程的反馈, 再发送对应的交互命令.
spawn 命令用来启动新的进程, spawn 后的 send 和 expect 命令都是和使用 spawn 打开进程进行交互.
interact 命令用的其实不是很多, 一般情况下使用 spawn,send 和 expect 命令就可以很好的完成我们的任务; 但在一些特殊场合下还是需要使用 interact 命令的, interact 命令主要用于退出自动化, 进入人工交互. 比如我们使用 spawn,send 和 expect 命令完成了 ftp 登陆主机, 执行下载文件任务, 但是我们希望在文件下载结束以后, 仍然可以停留在 ftp 命令行状态, 以便手动的执行后续命令, 此时使用 interact 命令就可以很好的完成这个任务.
结束符:
expect eof : 等待执行结束, 若没有这一句, 可能导致命令还没执行, 脚本就结束了
interact : 执行完成后保持交互状态, 这时可以手动输入信息
注: expect eof 与 interact 二选一即可
实例
下面通过一些常用的 expect 脚本来具体的说明如何使用 expect 来完成日常的一些工作.
这是一段非常简单的 expect 示例代码, 演示了 expect 的基本使用方法.
#!/usr/bin/expect: 使用 expect 来解释该脚本;
set timeout 30: 设置超时时间, 单位为秒, 默认情况下是 10 秒;
set host "xx.xx.xx.xx": 设置变量;
spawn SSH $username@$host:spawn 是进入 expect 环境后才可以执行的 expect 内部命令, 如果没有装 expect 或者直接在默认的 SHELL 下执行是找不到 spawn 命令的. 它主要的功能是给 SSH 运行进程加个壳, 用来传递交互指令;
expect "*password*": 这里的 expect 也是 expect 的一个内部命令, 这个命令的意思是判断上次输出结果里是否包含 "password" 的字符串, 如果有则立即返回; 否则就等待一段时间后返回, 这里等待时长就是前面设置的 30 秒;
send "$password\r": 当匹配到对应的输出结果时, 就发送密码到打开的 SSH 进程, 执行交互动作;
interact: 执行完成后保持交互状态, 把控制权交给控制台, 这个时候就可以手工操作了. 如果没有这一句登录完成后会退出, 而不是留在远程终端上.
这里其实涉及到 expect 中一个非常重要的概念 -- 模式 - 动作; 即上述 expect "*password*" {send "$password\r"} 这句代码表达出来的含义.
模式 - 动作
结合着 expect "*password*" {send "$password\r"} 这句代码来说说 "模式 - 动作". 简单的说就是匹配到一个模式, 就执行对应的动作; 匹配到 password 字符串, 就输入密码. 你可能也会看到这样的代码:
其中 exp_continue 表示循环式匹配, 通常匹配之后都会退出语句, 但如果有 exp_continue 则可以不断循环匹配, 输入多条命令, 简化写法.
传参
很多时候, 我们需要传递参数到脚本中, 下面看看如何在 expect 中使用参数:
在 expect 中,\$argc 表示参数个数, 而参数值存放在 $argv 中, 比如取第一个参数就是 [hwb $argv 0], 以此类推.
总结
能够在工作中熟练的使用 Shell 脚本可以很大程度的提高工作效率, 如果再搭配上 expect, 那么很多工作都可以自动化进行. 不过如果你会 Python 的话, 你的视野将会更加开阔, 那个时候你又会 "嫌弃"expect 了.
来源: http://os.51cto.com/art/201908/602189.htm