服务器诊所 Expect 超出预期 一种不为人知但功能强大的流行工具
- UID
- 1066743
|
服务器诊所 Expect 超出预期 一种不为人知但功能强大的流行工具
您是一名“系统程序员”― 您编写代码以保持服务器正常运转,并且为您的应用程序开发人员同事提供所需的底层功能。您从哪里获取所需的信息呢?大多数编程参考大全关心客户机或者“应用程序”问题,而管理书籍通常回避编程而致力于“配置”。
我希望您会发现这一新的“服务器诊所”专栏是有用的来源之一。每个月,我都将解决在服务器的“维护与支持”中遇到的一个编程问题或一类共同问题。
专栏第一部分将 Expect 作为您最应该了解的一种语言进行介绍。您可能已经熟悉 Expect 了。不过,您也可能从未见过 Expect 所管理任务的完整范围。Expect 实现了一种 Linux 系统编程的通用性,其它语言 ― 即使是 C、Java 或 bash ― 都无法与之相比。虽然未来的专栏文章将展示使用各种语言的解决方案,但 Expect 很可能是出现频率最高的一个。
在 Tcl 上构建什么使 Expect“通用”呢?首先,应了解 Expect 是 Tcl/Tk 编程语言的适当超集。Tcl 是在各种程序中使用的一种高级语言。它过去通常与 Perl、Python、Ruby 和其它语言一起被归为“脚本编制”语言。在 2002 年,最明智的做法是抛开某些历史事件,简单地将所有这些语言视为高效率的开放源码语言。Tcl 在计算机辅助设计(CAD)领域中特别流行,象 Cisco 和 Nortel 这样的联网设备供应商也都使用它。与其它“脚本编制”语言一样,Tcl 的内置功能适用于文本处理、数据库管理、联网和算法等领域中的最常见问题。
Tcl 是 Expect 的基础。任何 Tcl 程序都自动是 Expect 程序。因为有下面两个原因,所以强调这一点很重要:
- 许多人只知道 Expect 是一种“工具”,而从不了解它是一种完全成熟的编程语言。
- 1994 年,许多真正认识到 Expect 的通用能力的程序员都被它迷住了。
Expect 的作者是(美国)国家标准与技术协会(National Institute of Standards and Technology)的 Don Libes。他在 1994 年出版了一本关于 Expect 的出色书籍。该书现在仍只有第一版,它没有竞争者;这本书写得太好了,以至于没有出版商出版另一本书。最引人注目的是, Exploring Expect(请参阅本文后面的 )一直不需要更新。它的清晰和精确很好地经受了时间的考验。
这里的问题是,过去八年以来,Expect 的底层 Tcl 基础已经有了极大发展。最初编写 Expect 时,Tcl 并不追求成为通用的编程语言。从那时起,Tcl 已经:
- 知道如何处理完整的八位数据,甚至能方便地处理 Unicode;
- 添加了方便的 TCP/IP 抽象;
- 获取了数据和时间计算以及格式化方面的能力;
- 改进并合理化了其字符串处理;
因此,请记住:如果 Perl、Java 或 C 可以解决一个问题,那么 Tcl 以及 Expect 很可能也可以解决。
Tcl 有一项任何其它编程语言都“无与伦比(out of the box)”的工作,这就是图形用户界面(GUI)的构建。虽然从 ActiveState Tools Corporation 下载的 Linux 版标准 ActiveTcl 二进制分发版只有大约 10 兆字节,但它不仅包含 Expect,而且还包含功能齐全的集成 GUI 工具箱。下面的示例将说明这个名为“Tk”的工具箱如何简洁地表达 GUI 解决方案。
难题的独特解决方案Expect 的 Tcl/Tk 基础适用于范围非常广的编程。请记住,Expect 可以完成 Tcl/Tk 所能做的一切。除此之外,Expect 添加了三大类别的附加功能:
- 扩展的调试选项
- 描述面向字符对话框的便利命令
- 棘手的面向字符终端的独一无二的管理
这些功能中第一个是常规的。Expect 有各种“开关”来记录或报告其操作的各个方面。
Expect 的用途是使面向字符的交互自动化。您可能已经自己完成了许多这种工作。每次编写命令行管道或重定向输入/输出(I/O)流时,您都在让计算机管理这些工作,否则您必须自己输入。
Expect 以两种方式深化了这一控制:首先,它提供了表达对话框复杂程度的语言。Expect 不只使用固定“脚本”作为应用程序的输入,而是使交互的每个击键都可编程。
如 Libes 所说,更关键的是:“最终,Expect 是为处理蹩脚的界面而设计的工具。”特别是 Expect 具有管理抵制 I/O 重定向的应用程序的能力。典型示例是命令行 passwd 程序。每个负责管理服务器的人员迟早都需要使密码更新自动化。第一次尝试可能是作为 root 用户运行类似下面的代码:
失败的 passwd 自动化1
2
3
4
| passwd $user << HERE
$newpassword
$newpassword
HERE
|
正如每个尝试它的人很快会发现,这根本不起作用。shell 的 < 和 << 重定向对于象 passwd 这样的程序不起作用。
但是,Expect 可以使重定向起作用。Expect 知道如何与所有面向字符的应用程序对话,即使是象 passwd 那样操纵终端设置的应用程序。
正是这一点完善了 Expect 的通用性。原则上,其它语言或库可以提供终端特征的信息。例如,Perl 的 Expect.pm 模块在这方面已经做了很多。虽然经过十多年生产使用,但却没出现其它有力的竞争对手。
这就是您应该学习 Expect 的原因。您将处理带有“蹩脚界面”的程序 ― 您周围有很多这样的程序 ― 而 Expect 通过让它们完成您所需的工作,可以减少几小时甚至几天的开发时间。同时,还可以将 Expect 用于通常由 bash 或 Perl 完成的所有作业。
有关 Expect 的所有其它须知信息您还应该了解有关 Expect 的其它信息。本专栏的最后部分包括对 Expect 局限的说明、对解决常见问题的 Expect 工作代码的概述以及可以引导您更深入了解 Expect 编程的参考。
Expect 所做的比大多数人所认识到的要多;这就是本专栏的主题。Expect 也有不足之处。系统程序员通常需要使象 FTP 操作、电子邮件发送或处理以及 GUI 测试这样的任务自动化。对于其中的前两项,Expect 无法提供帮助。更准确地说,虽然可以使用 Expect 来使 FTP 和电子邮件自动化(这样做在前几年也很常见),但是现在 Expect 在这些领域方面没有特别优势。其它语言和方法与面向 Expect 的编码功效相同,或者更胜一筹。这个“服务器诊所”专栏的未来部分将说明简便联网自动化的示例。
Expect 的著名用法是用于测试。Expect 是用于几个高端产品(包括 gcc)质量控制中使用的 DejaGnu 系统的基础。然而,虽然 Expect 可用于构建 GUI,并且在几个测试框架中也很关键,但是通常 Expect 在用于 GUI 系统的测试框架中 不起作用。
暂时回到上面提到的 passwd 问题。Expect 对它的展望是什么呢?
要了解 Expect 源代码,目前更简便的做法是忽略安全性考虑事项。下面的程序需要作为 root 用户运行。Expect 提供有用的功能以实现更安全的操作;不过在掌握 Expect 基础知识后更容易理解这些。
您已经知道简单 I/O 重定向对 passwd 不起作用。何种 Expect 程序提供了更好的结果呢?
更新密码的简单 Expect 程序1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Invoke as "change_password <user> <newpassword>".
package require expect
# Define a [proc] that can be re-used in many
# applications.
proc update_one_password {user newpassword} {
spawn passwd $user
expect "password: "
exp_send $newpassword\n
# passwd insists on verifying the change,
# so repeat the password.
expect "password: "
exp_send $newpassword\n
}
eval update_one_password $argv
|
这就是 Expect 用来使程序自动化所需的全部代码,其它语言几乎不可能做到。再多用几行,您可以一次对成百上千用户进行批处理更新。这是一种常见需求;我经常被请去恢复密码文件被严重毁坏的服务器,这里说明了一种开始的方法:
简单迭代1
2
3
4
5
6
7
| ...
set default_password lizard5
set list [exec cat list_of_accounts]
foreach account $list {
update_one_password $account $default_password
puts "Password for '$account' has been reset."
}
|
同样适用于 GUI给 Expect 自动化加上 GUI 外观也只需要多加几行。假定您想为一名非程序员提供方便地更新密码的应用程序。同样忽略安全性考虑事项,这就象完成下列代码一样简单:
简单迭代1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| ...
package require Tk
frame .account
frame .password
label .account.label -text Account
entry .account.entry -textvariable account
label .password.label -text Password
# Show only '*', not the real characters of
# the entered password.
entry .password.entry -textvariable password -show *
button .button -text "Update account" -command {
update_one_password $account $password
}
pack .account .password .button -side top
pack .account.label .account.entry -side left
pack .password.label .password.entry -side left
|
这个小工作应用程序具有下面的视觉外观:
简单 Expect 密码管理器的抓屏结束语Expect 具有系统程序员通常需要的独特能力。同时,Expect 是出色的通用编程语言,它在联网和 GUI 构造方面具有优势。如果您必须只选择一种用于日常工作的语言,Expect 近乎是理想选择。 |
|
|
|
|
|