我有分寸

一点expect心得

gnawux expectexpect_outexp_continuefull_bufferscriptstcl

最近用了几下 expect,  记几个心得,以备不时之需

循环式匹配: exp_continue

expect 的匹配可以看做是一个循环,通常匹配之后都会退出语句,但如果有 exp_continue 则可以不断循环匹配,输入多条命令

expect{
    "$passprompt"    { send "$password"; exp_continue }
    "$prompt" {send "$c\r"}
}

在这个例子里,遇到密码提示的时候,送出密码,然后继续 expect,遇到命令提示,送出命令,然后退出 expect,当然,可以做得更复杂,一条一条送命令,送没了再退出。这样,expect 的结构会比较漂亮,而且容易扩展。

正则匹配: -re

作为一种 tcl 的分支,expect 支持 tcl 的正则表达式,正则表达式这里就不多说了,正则匹配的一个重要用途是,对多个匹配关键字进行相同的操作,比如

expect {
    -re "$prompt|$rootprompt" { send "$c\r" }
}

这里是对普通用户的提示和root用户的提示进行同样的操作。

利用PS1环境变量

在 expect 里,根据程序的返回状态做操作不是件容易事,很多做法都不是十分干净,我的一个方法是,根据 $? 的值设置 PS1 环境变量,这样,下一次出现的 Shell 提示就不是之前的提示了,只要特别 expect 这个提示,进行操作就行了。

嗯,这算是个野路子,不正规哈,欢迎指正。

抓取远程的输出到本地:expect_out 和 full_buffer

我们经常需要抓取远程的输出,这时,可以借助 expect_out 来抓取两次 expect 之间的内容,它有两个用法:

  • expect_out(buffer) 这个直接抓取两次 expect 之间的全部 buffer
  • expect_out(1,buffer) 这个抓取正则匹配的部分

后者这里不多说了,前者有个问题,就是当两条命令之间输出很多时,可能 buffer 会满,在这种情况下,expect_out(buffer) 不是全部的 buffer 内容,而是最后的,这时要靠 full_buffer 帮助了,这里举个例子

set result ""
expect {
    "$prompt" {
        append result $expect_out(buffer)
        puts stderr $result
        set result ""
        send "$newcmd"
        exp_continue 
    }
    full_buffer {
        append result $expect_out(buffer)
        exp_continue
    }
}

这时个示例,注意 full_buffer 是特殊匹配事件,类似 timeout,不是字符串。

嗯,暂时记这些吧。

gnawux
me!#$!@#$@#$wangxu!@#$%^&*()_me