一种不为人知但功能强大的流行工具

发表于:2007-07-04来源:作者:点击数: 标签:
您是一名“系统 程序员 ”— 您编写代码以保持 服务器 正常运转,并且为您的应用程序 开发 人员同事提供所需的底层功能。您从哪里获取所需的信息呢?大多数编程参考大全关心客户机或者“应用程序”问题,而管理书籍通常回避编程而致力于“配置”。 我希望您

  您是一名“系统程序员”— 您编写代码以保持服务器正常运转,并且为您的应用程序开发人员同事提供所需的底层功能。您从哪里获取所需的信息呢?大多数编程参考大全关心客户机或者“应用程序”问题,而管理书籍通常回避编程而致力于“配置”。
  
  我希望您会发现这一新的“服务器诊所”专栏是有用的来源之一。每个月,我都将解决在服务器的“维护与支持”中遇到的一个编程问题或一类共同问题。
  
  专栏第一部分将 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 自动化
  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 是用于几个高端产品(包括 gclearcase/" target="_blank" >cc)质量控制中使用的 DejaGnu 系统的基础。然而,虽然 Expect 可用于构建 GUI,并且在几个测试框架中也很关键,但是通常 Expect 在用于 GUI 系统的测试框架中不起作用。
  
  暂时回到上面提到的 passwd 问题。Expect 对它的展望是什么呢?
  
  要了解 Expect 源代码,目前更简便的做法是忽略安全性考虑事项。下面的程序需要作为 root 用户运行。Expect 提供有用的功能以实现更安全的操作;不过在掌握 Expect 基础知识后更容易理解这些。
  
  您已经知道简单 I/O 重定向对 passwd 不起作用。何种 Expect 程序提供了更好的结果呢?
  
  更新密码的简单 Expect 程序
    # 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 用来使程序自动化所需的全部代码,其它语言几乎不可能做到。再多用几行,您可以一次对成百上千用户进行批处理更新。这是一种常见需求;我经常被请去恢复密码文件被严重毁坏的服务器,这里说明了一种开始的方法:
  
  简单迭代 
     ...
    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 外观也只需要多加几行。假定您想为一名非程序员提供方便地更新密码的应用程序。同样忽略安全性考虑事项,这就象完成下列代码一样简单:
  
  简单迭代
    ...
  
    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 密码管理器的抓屏
  
javascript:window.open(this.src);" style="CURSOR: pointer" onload="return imgzoom(this,550)">

  结束语
  Expect" 具有系统程序员通常需要的独特能力。同时,Expect 是出色的通用编程语言,它在联网和 GUI 构造方面具有优势。如果您必须只选择一种用于日常工作的语言,Expect 近乎是理想选择。
  
  请告诉我您如何使用 Expect 以及想让它为您做什么。在以后的几个月,这个“服务器诊所”专栏将回头研究高端版本控制、网络代理和更多的自动化。在那以前,祝您和您的服务器都“身体健康”。

原文转自:http://www.ltesting.net