Board logo

标题: Tcl/Tk 快速入门 开始认识 Expect [打印本页]

作者: look_w    时间: 2018-4-16 21:11     标题: Tcl/Tk 快速入门 开始认识 Expect

Expect 是什么?Expect 是 Tcl 和 Tk 语言的扩展。Expect 为使交互式程序的脚本编制自动化,提供了简单而功效强大的接口。另外,Expect 使交互式应用程序嵌入 GUI 变得容易。Expect 的开发与 Tcl/Tk 的出现是同时发生的,两者目前的版本都是 5.32。
Expect 的作者是 Don Libes,他在美国国家标准与技术学会(NIST)工作。驻留在 NIST 服务器上。(然而,Expect 和任何相关的商业或非商业产品显然都未经 NIST 认可。)在下面几屏中,将研究从源代码示例目录中精选出来的一些 Expect 脚本示例,并简要概述它的命令语法。
为什么要学习 Expect?引用 Don 论文中的一句话,“使用 expect,使系统管理任务自动化”(USENIX LISA 会议 1990 年 10 月)“……结果是 UNIX 系统管理员的工具箱里充斥着曾经见到过的一些最差的用户界面。只有完全重新设计才能帮助解决所有这些问题,expect 可用来处理许多这些问题。”
使用 Expect 的 RFC 检索
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/local/bin/expect --

# ftp-rfc <rfc-number>
# ftp-rfc -index

# retrieves an rfc (or the index) from uunet

exp_version -exit 5.0

if {$argc!=1} {
  send_user "usage: ftp-rfc \[#] \[-index]\n"
  exit
}

set file "rfc$argv.Z"

set timeout 60
spawn ftp ftp.uu.net
expect "Name*:"
send "anonymous\r"
expect "Password:"
send "bilbrey@orbdesigns.com\r"
expect "ftp>"
send "binary\r"
expect "ftp>"
send "cd inet/rfc\r"
expect "550*ftp>" exit "250*ftp>"
send "get $file\r"
expect "550*ftp>" exit "200*226*ftp>"
close
wait
send_user "\nuncompressing file - wait...\n"
exec uncompress $file




在介绍 Expect 之前,请先研究左边的示例。它只是对在标准 Expect 源代码分发版的示例目录中的版本略加修改而得到的,所有示例都在这个目录下。让我们看一下代码……
这个程序使 UUNet 档案文件中 IETF RFC(Request for Comment)文档的 FTP 检索自动化。脚本的第一行调用 Expect 外壳。注意,我已经给出了可执行文件的完整路径名。这是最安全的,因为很难知道任何给定用户的路径环境。该脚本先检查 Expect 版本,然后打印用法消息,除非给出正确的自变量数目。
接下来,设置 timeout 值,在下一行产生的 FTP 会话无法正确连接时,防止 Expect 脚本锁住系统资源。脚本的其余部分大多数是几组 expectsend 命令对。每个 expect 命令等待来自产生程序(在本例中是 ftp)的指定输出,后 send 正确响应。注意,在 cd 和 get 指令之后有两个 ftp 错误代码的陷阱。对于每种情况,错误代码 550 与第一个条件匹配,如果为真,则脚本存在。否则,执行 250 代码(表示成功),expect 进入下一条命令。
接收文档之后,脚本向 ftp 会话发出 close 命令。wait 命令挂起脚本处理,直到 ftp 终止为止。最后,脚本将给用户发送一个消息,对已下载的 RFC(或 rfc 下标)进行解压,然后隐式退出(缺省情况下)。
Expect 的关键,第 1 部分
1
2
3
4
5
6
7
8
9
10
11
#!../expect -f
# wrapper to make passwd(1) be non-interactive
# username is passed as 1st arg, passwd as 2nd

set password [lindex $argv 1]
spawn passwd [lindex $argv 0]
expect "password:"
send "$password\r"
expect "password:"
send "$password\r"
expect eof




Expect(作为语言,‘E’大写)有四个关键命令。第一个是 expect(命令,小写‘e’),如果找到匹配,它搜索模式并执行命令。对于每条 expect 命令,可以有几个组,每个组都是由选项标志、与之匹配的模式以及要执行的命令或命令主体组成。缺省情况下,expect“侦听”SDTOUT 和 STDERR,直到找到匹配或 timeout 期满为止。
缺省情况下,使用 Tcl 的字符串匹配设施来匹配模式,它实现文件名替换,类似于 C 外壳模式匹配。-re 标志调用 regexp 匹配,-ex 表明必须是精确匹配,不带通配符或变量扩展。expect 的其它可选标志包括 -i 和 -nocase,前者表示要监控产生的进程,后者强迫在匹配之前将进程输出变为小写。对于完整的说明,在命令提示符下输入 man expect,以查看 Expect 的系统手册页面文档。
第二个重要命令是 send,它用于为由 Expect 脚本正在监控的进程生成输入。send 合并选项以发送给指定的产生的过程(-i),缓慢地发送(-s,例如,在串行通信中,为了不使缓冲区溢出)以及其它几个选项。
Expect 的关键,第 2 部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/local/bin/expect
# Script to enforce a 10 minute break
# every half hour from typing -
# Written for someone (Uwe Hollerbach)
# with Carpal Tunnel Syndrome.
# If you type for more than 20 minutes
# straight, the script rings the bell
# after every character until you take
# a 10 minute break.

# Author: Don Libes, NIST
# Date: Feb 26, '95

spawn $env(SHELL)

# set start and stop times
set start [clock seconds]
set stop [clock seconds]

# typing and break, in seconds
set typing 1200
set notyping 600

interact -nobuffer -re . {
  set now [clock seconds]

  if {$now-$stop > $notyping} {
    set start [clock seconds]
  } elseif {$now-$start > $typing} {
    send_user "\007"
  }
  set stop [clock seconds]
}




左边是称为 carpal 的脚本,它也是来自源代码 Expect 分发版的另一个示例。
spawn 是用于创建新进程的 Expect 命令。它已经出现在我们使用过的每个示例中。在左边,它把路径拖到缺省外壳可执行文件并产生新实例。在这样做时,spawn 返回一个进程标识(在变量 spawn_id 中设置)。这可以在脚本中保存并设置,这给予了 expect 进程控制能力。
interact 是 Expect 用来打开用户与产生进程之间通信的命令。-nobuffer 标志将与模式匹配的字符直接发送给用户。-re 告诉 interact 将接下来的模式用作标准正规表达式,‘.’是与输入时每个字符匹配的模式。在交互方式中,缺省情况下,Expect 的 STDOUT 和 STDERR 流的重定向也返回给用户。
使用 Expect 可以完成哪些任务?当脚本调用交互式程序时,缺省情况下,Expect 拦截所有输入和输出(STDIN、STDOUT 和        STDERR)。这允许 Expect 搜索与程序输出匹配的模式,并将输入发送到产生的进程,以模拟用户交互。另外,Expect 可以将进程的控制传递给用户(如果这样指示的话),或者根据请求控制。
这些特性不仅使 Expect 对于公共管理任务变得非常有用,而且证实了 Expect 有益于构建测试脚本,以在程序开发期间执行 I/O 验证。
最后,有一个极其有用的程序 autoexpect。它本身是一个 Expect 脚本,autoexpect 监控命令行交互式程序,生成精确复制该交互的        Expect 脚本。现在,虽然通常不需要它,但很容易拿几个 autoexpect 会话的结果,概括 expect 模式,然后将它们剪贴到期望的配置中。已经在多处提到过,学习 Expect 的最佳工具是运行 autoexpect 并使用这些结果。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0