很容易在“小语言”的世界中迷失方向 —— 它们中相当多是出于一个公司、个人或者一个项目的特殊需要而编写出来的。Rexx 就是这些语言中的一个,已经在 IBM 的操作系统上使用很长时间了,而且令人满意的最新实现可以用于 Linux 和其他免费软件操作系统。在相对粗糙的 shell 脚本和笨重的拘泥形式的完全系统语言的夹缝之中,Rexx 有其用武之地。Rexx 值得很多 Linux 程序员和系统管理员将其添加到收集的关键工具中。
关于 Rexx
Rexx 编程语言最初创建于 1979 年,是一个层次非常高的脚本语言,有特别强大的用于文本处理任务的工具。从 Rexx 诞生起,IBM 就将各种版本的 Rexx 加入到它的操作系统中 —— 从主机到中型机再到终端用户操作系统,比如 OS/2 和 PC-DOS。其他 OS 制造商,比如 Amiga,也将 Rexx 作为永远可用的系统脚本语言集成进来。此外,许多独立软件开发商为很多平台创建了 Rexx 环境。再晚些时候,ANSI 于 1996 年正式为 Rexx 采纳了一个标准。
当前(尤其是在 Linux 或者起源于 BSD 的 OS 上),Rexx 的那些大部分早期实现,主要作为历史足迹为人们所关心。不过,两个当前保持的 Rexx 实现可以用于包括 Linux、MacOSX 和 Windows 在内的许多平台:Regina 和NetRexx。Regina 是本地执行文件,以免费软件源代码方式,或者为诸多平台预编译好的方式获得 —— 您可以像安装任何其他语言解释器一样安装它。NetRexx 是一个有趣的“混合物”。此语言派生自普通的 Rexx。更类似于 Jython 或者 Jacl,NetRexx 将类似于 Rexx 源代码编译为 Java 字节代码,并(可选)在 JVM 中运行作为结果生成的 .class
文件。
NetRexx 是一个 IBM 项目,用于为 Java 虚拟机编译类似于 Rexx 的代码。在实际能力和编程级别上,Rexx 最接近于 bash
加上 GNU 文件工具(外加 grep
和 sed
);或者可能相当于 awk
或 Perl。当然,相对于 Python、Ruby 或者 Java 来说,Rexx 让人感觉更为快而粗糙。Rexx 的冗长 —— 或者更应该说是,简洁 —— 类似于 Perl、Python、Ruby 或者 TCL。并且,Rexx 当然是完全 Turing 的,支持模块和结构化编程,有面向专门任务的库,例如 GUI 接口、网络编程和数据库访问。但是它最自然的目标在于系统脚本的自动化和本文处理任务。与 shell 脚本一起,Rexx 使得应用程序的控制非常自然且显而易见;但相对于 bash
(或者 tcsh
、 ksh
等等),Rexx 中包含了更丰富的内置控制结构和(文本处理)函数。
在文体上,Rexx 的 IBM/mainframe 根源体现在它对命令的大小写敏感;在某种次要程度上也体现在它使用标点符号相对较少 (更多用关键字而不是符号)。我倾向于认为这些特性的目的是提高可读性;但这在很大程度上取决于个人的爱好。
从流和栈开始
作为一个简单的小例子,让我来介绍一个特别简单的工具的多个版本,它可以列出文件并对其进行编号。Rexx 和 shell 脚本的一个共同点是,它用于和底层操作系统打交道的函数相对很少 —— 几乎仅限于可以打开、读和修改文件。对大部分其他事情,您需要依赖于外部实用程序来完成手头上的工作。实用程序 numbered-1.rexx
只是处理 STDIN:
清单 1. numbered-1.rexx
#!/usr/bin/rexx
DO i=1 UNTIL lines()==0
PARSE LINEIN line
IF line\="" THEN
SAY i || ") " || line
END
|
无处不在的指令 PARSE
可以从各种不同的源读入。在这里,它将 STDIN 的下一行赋给变量 line
。我们也会检查某一行是否为空,如果是空的话,则不进行显示和编号。例如,与 ls
组合使用我们可以得到:
清单 2. 将命令通过管道传输到 numbered-1
$ ls | ./numbered-1.rexx
1) ls-1.rexx
2) ls-2.rexx
3) ls-3.rexx
4) ls-4.rexx
5) ls-5.rexx
6) ls-6.rexx
7) numbered-1.rexx
8) numbered-2.rexx
|
同样您可以方便地将任何其他命令通过管道传输进来。
Rexx 的核心概念之一是巧妙地处理多个栈或流。类似 bash
的风格,在 Rexx 中任何没有被识别为内部指令或函数的内容,都被假定为一个外部实用程序。没有特定的函数或语法用于调用外部命令。Regina 的实用程序 rxqueue
可以将输出压入 Rexx 栈,利用它我们可以写一个这样的“有编号的 ls”实用程序:
清单 3. ls-1.rexx
#!/usr/bin/rexx
"ls | rxqueue"
DO i=1 WHILE queued() \= 0
PARSE PULL line
SAY i || ") " || line
END
|
Rexx 中有一些指令可以显式地指定要操作的栈;但是其他指令操作是在您用 ADDRESS
指令配置的 环境 中进行。STDIN、STDOUT、STDERR、文件和内存内部数据栈都以统一而优雅的方式处理。上面我们用的是外部 rxqueue
实用程序,不过在 Rexx 内部我们同样可以重定向实用程序的输出。例如:
清单 4. ls-2.rexx
#!/usr/bin/rexx
ADDRESS SYSTEM ls WITH OUTPUT FIFO '' ERROR NORMAL
DO i=1 WHILE queued() \= 0
PARSE PULL line; SAY i || ") " || line; END
|
[1] [2] [3] 下一页