原文地址 : Linux 下使用 expect 实现跳板机自动跳转/免密登录/自动登录(转)
Expect 是一个用来处理 交互 的命令。借助 Expect,我们可以将交互过程写在一个脚本上,使之自动化完成。形象的说,ssh 登录,ftp 登录等都符合 交互 的定义。
四个命令
Expect 中最关键的四个命令是 send,expect,spawn,interact。

  • send:用于向进程发送字符串
  • expect:从进程接收字符串
  • spawn:启动新的进程
  • interact:允许用户交互

    1. send 命令

    send 命令接收一个字符串参数,并将该参数发送到进程。
    1. expect1.1> send "hello word\n"
    2. hello word
    3. expect1.2>

    2. expect 命令

    2.1 基础知识

    expect 命令和 send 命令正好相反,expect 通常是用来等待一个进程的反馈。expect 可以接收一个字符串参数,也可以接收正则表达式参数。和上文的 send 命令结合,现在我们可以看一个最简单的交互式的例子:
    1. expect "hi\n"
    2. send "hello there!\n"
    这两行代码的意思是:从 标准输入 中等到 hi 和换行键后,向 标准输出 输出 hello there。

    $expect_out(buffer) 存储了所有对 expect 的输入,<$expect_out(0,string)> 存储了匹配到 expect 参数的输入。

比如如下程序:

  1. expect "hi\n"
  2. send "you typed <$expect_out(buffer)>"
  3. send "but I only expected <$expect_out(0,string)>"

当在标准输入中输入

  1. test
  2. hi

是,运行结果如下

  1. you typed: test
  2. hi
  3. I only expect: hi

2.2 模式-动作

expect 最常用的语法是来自 tcl 语言的模式-动作。这种语法极其灵活,下面我们就各种语法分别说明。
单一分支模式语法:

  1. expect "hi" {send "You said hi"}

匹配到 hi 后,会输出”you said hi”
多分支模式语法:

  1. expect "hi" { send "You said hi\n" } \
  2. "hello" { send "Hello yourself\n" } \
  3. "bye" { send "That was unexpected\n" }

匹配到 hi, hello, bye 任意一个字符串时,执行相应的输出。等同于如下写法:

  1. expect {
  2. "hi" { send "You said hi\n"}
  3. "hello" { send "Hello yourself\n"}
  4. "bye" { send "That was unexpected\n"}
  5. }

3. spawn 命令

上文的所有 demo 都是和标准输入输出进行交互,但是我们跟希望他可以和某一个进程进行交互。spawn 命令就是用来启动新的进程的。spawn 后的 send 和 expect 命令都是和 spawn 打开的进程进行交互的。结合上文的 send 和 expect 命令我们可以看一下更复杂的程序段了。

  1. set timeout -1
  2. spawn ftp ftp.test.com //打开新的进程,该进程用户连接远程ftp服务器
  3. expect "Name" //进程返回Name时
  4. send "user\r" //向进程输入anonymous\r
  5. expect "Password:" //进程返回Password:时
  6. send "123456\r" //向进程输入don@libes.com\r
  7. expect "ftp> " //进程返回ftp>时
  8. send "binary\r" //向进程输入binary\r
  9. expect "ftp> " //进程返回ftp>时
  10. send "get test.tar.gz\r" //向进程输入get test.tar.gz\r

这段代码的作用是登录到 ftp 服务器 ftp ftp.uu.net 上,并以二进制的方式下载服务器上的文件 test.tar.gz。程序中有详细的注释。

4. interact

到现在为止,我们已经可以结合 spawn、expect、send 自动化的完成很多任务了。但是,如何让人在适当的时候干预这个过程了。比如下载完 ftp 文件时,仍然可以停留在 ftp 命令行状态,以便手动的执行后续命令。interact 可以达到这些目的。下面的 demo 在自动登录 ftp 后,允许用户交互。

  1. spawn ftp ftp.test.com
  2. expect "Name"
  3. send "user\r"
  4. expect "Password:"
  5. send "123456\r"
  6. interact

解决问题

1. 如何从机器 A 上 ssh 到机器 B 上,然后执行机器 B 上的命令?使之自动化完成?

下面一段脚本实现了从机器 A 登录到机器 B,然后执行机器 B 上的 pwd 命令,并停留在 B 机器上,等待用户交互。具体含义请参考上文。

  1. #!/home/tools/bin/64/expect -f
  2. set timeout -1
  3. spawn ssh $BUser@$BHost
  4. expect "*password:" { send "$password\r" }
  5. expect "$*" { send "pwd\r" }
  6. interact

2. 如何实现登录到跳板机然后再登录到其他机器

  1. #! /usr/bin/expect
  2. set JumpPwd [lindex $argv 0]
  3. set ServerHost [lindex $argv 1]
  4. set ServerPwd [lindex $argv 2]
  5. set timeout 3
  6. spawn ssh server-jump
  7. expect {
  8. "yes/no" {
  9. send "(yes/no)\\?";
  10. exp_continue;
  11. }
  12. "*passphrase*" {
  13. send "$JumpPwd\r"
  14. }
  15. }
  16. # next jump
  17. expect "*user@*" {
  18. send "ssh $ServerHost\r"
  19. }
  20. expect {
  21. "*passphrase*" {send "$ServerPwd\r"}
  22. }
  23. interact

参考

  • expect - 自动交互脚本