1.TCL/TK脚本学习——入门基础
Tcl/Tk有两个主要程序。是 tclsh 和 wish。前者是 Tcl 外壳,常用于为外壳脚本提供执行环境。Wish类似于 tclsh,它是针对窗口化的 GUI环境。
第一个例子
创建一个文件hello.tcl内容如下:
puts stdout {hello,World!}
然后执行
#tclsh hello.tcl
输出如下:
hello,World!
如果带参数如下:
if {$argc >= 1} {
set N 1
foreach Arg$argv {
putsstdout "$N: $Arg\n"
set N[expr $N + 1]
if{$Arg == "ring"} {
puts stdout "\a"
}
}
} else {
puts stdout"$argv0 \n"
}
执行后如下:
#tclsh hello.tcl 1 23 ring 3 ring
1: 1
2: 23
3: ring
4: 3
5: ring
argc是对脚本自变量的计数,而不是对调用的名称进行计数。 argv 是自变量的列表(不是数组)。argv0 是调用的文件名(可以是符号链接)
\char 允许替代非打印 ASCII字符。这对于 UNIX下的许多脚本语言和外壳环境都是常见的。如表中说明的那样,对于没有定义替代的反斜杠引用的字符只被简单地回送到输出。
\字符 |
替代 |
\a |
响铃 |
\b |
退格 |
\f |
换页 |
\n 或 \newline |
新行 |
\r |
回车 |
\t |
水平制表 |
\v |
垂直制表 |
\space ("\ ") |
空格 |
\ddd |
八进制值 |
\xddd... |
十六进制值 |
\c |
回显‘c’ |
\\ |
反斜杠 |
字符串和模式匹配
字符串是 Tcl中的基本数据类型。string 命令实际上是一组命令,这些命令都是属于 string的。在使用中,正如在左边的示例中所看到,string 读取的方式非常象来自 OOP编程特定对象方法的应用程序。
Tcl 列表
列表在 Tcl中有两个主要用途。在通过 foreach 命令(在 Tcl中的循环和分支中找到)处理命令行自变量。第二个用途是动态地构建 Tcl命令的元素,可以看到使用 eval命令来执行这种用途。
list 命令接受它的所有自变量并将它们返回在一个列表环境中。自变量可以是值或变量。在左边这个示例中,可以手工创建列表,或可将其它列表视作自变量来使用列表(从而保存第一个“Party”的两对方向)。或者,concat 命令用于将两个或多个列表合并到*项的单个实体,返回第二个更有趣的“Party”。
Tcl 数组
理解 Tcl数组的捷径是,将它们视作与 Perl散列相同的东西。Tcl数组不是用数字建立下标的线性数据结构,除非选择对数据强加那种解释。尽管带空格的字符串需要用引号括起或需要一个变量引用,但下标(或键)可以是任何字符串。
正如一般的变量一样,使用 set 命令初始化数组,如左边所示。圆括号内是给出的下标部分。请注意,圆括号不象花括号或双引号那样提供分组。一旦初始化为数组,就不能将变量作为单一变量来访问。如左边列表底部所示,数组元素也可以是列表。
更多 Tcl 数组
array 命令是一种多用途工具,很象 string。array exists 命令用于测试变量是否作为数组存在,arrayget 用于将数组转换成列表格式,arrayset用于将列表转换为数组,array names 用于返回下标列表,array size 用于返回对下标进行计数的结果。搜索整个数组有它自己的一组四个命令:array startseach、array anymore、arraynextelement 和 arraydonesearch。
变量作用域规则
作用域规则描述了过程和变量名以及值在程序的不同层次上的可见性。例如,在脚本的最外层定义的变量是全局变量。缺省情况下,全局变量是不可见的,在过程内部也不可用它们的值。这允许过程的编写者*地定义变量名并赋值,而不必担心覆盖对于局部作用域上未知的重要变量。要使全局变量在过程内部变得可见,必须将它声明为在过程内,使用 global 命令那样。
upvar 命令提供将局部变量与另一个作用域中变量的值相关联的设施。这允许根据名称将变量调用进过程,这对于当过程需要可以修改在另一个作用域的值而不仅仅使用它时,就显得非常方便。这个命令语法是 upvar level$VarName LocalVar,其中 level 是到当前作用域之外的步骤数。“#0”表示全局作用域这一层。
路径和文件
文件和路径操作是跨平台环境中具有挑战性的问题。对于主机 OS,Tcl使用 UNIX路径名(缺省情况下,用‘/’字符分隔)和本机路径名结构。即使当程序内的数据构造正确时,也很难确保用户输入与系统需求匹配。file join 命令用于将 UNIX格式转换成本机路径名。其它路径字符串命令包括 file split、dirname、file extension、nativename、pathtype 和 tail。
在它扮演的“工具控制语言”角色中,Tcl有许许多多种内部文件测试和操作功能。每条命令都以 file 开始,正如 file exists name 中一样。其它测试命令(它们都返回布尔值)包括 executable、isdirectory、isfile、owned、readable 和 writable。
文件信息和操作(再提醒您一次,所有都是以 file 开始)是通过atime、attributes、copy、delete、lstat、mkdir、mtime、readlink、rename、rootname、size、stat 和 type 来完成。请注意,在Windows或 Mac环境中运行一些文件信息命令时,可能会返回未定义的数据,因为例如在那些文件系统中没有表示索引节点和符号(和硬)链接数据。
使用 file ... 命令而不使用通过 exec 的本机命令的好处在于,前者会提供一个可移植接口。
Tcl 进程和文件 I/O
exec 命令用于显式地执行外部命令。在 Linux 下,当 Tcl 处于交互方式时,可以直接运行大多数外部命令,如左边示例所示。用 exec 运行时,会将程序的 stdout 输出返回到 Tcl,而不是返回到屏幕,这允许将数据赋值给变量。当程序在后台启动时,立即返回的值是程序的 PID。exec 程序可以充分利用 UNIX 环境中的 I/O 重定向和管道。
其它进程命令有 exit(终止正在运行的 Tcl 脚本)和 pid(返回当前或指定进程的 PID),对于出于各种目的的情况,这非常便利。Tcl 不合并任何本机进程控制命令,但可以将 exec 命令与 PID 数据一起使用来实现许多任务。
文件操纵使用下列命令:open、close、gets、puts、read、tell、seek、eof 和 flush。如左边所示,在文件打开命令期间 catch 命令对错误检查是有用的。当在遇到新的一行字符之前需要打印程序输出时,如在用户数据提示符中,使用 flush 来写输出缓冲区。另外一个功能(在受支持的环境中)是以打开文件的方式打开管道的能力。例如,用 set Channel [open"|sort foobar" r] 打开管道通道后,第一个 gets 的输出将是“Eight”(文件数据“One”到“Ten”的输出在 10 个单独的行上按字母顺序排列)。
将 eval 用于动态脚本
创建文件input01.txt
内容如下:
1 + 2
4 + 5
7 - 9
然后执行如下:
set InFile [open input01.txt r]
while {[gets $InFile Op] >=0} {
set Operation "expr $Op"
set Result [eval $Operation]
puts stdout "$Op = $Result\n"
}
结果如下:
1 + 2 = 3
4 + 5 = 9
7 - 9 = -2
在这个示例中,您可以感到 eval 命令的强大功能。在正常情况下,Tcl 解释器以一遍方式(one-pass)操作:它首先对输入的命令行(可能延伸在几个物理行上)进行解析,并执行任何替代。然后开始执行,除非找到不正常或残缺命令。eval 允许第二遍方式(second pass)(或许更精确地讲,是预通过(pre-pass))。因而,可以先动态构造 Tcl 命令,然后进行解析并执行它。
在左边的列表中,输入文件由三行组成,每行都显示了一种算术运算。调用 tclsh 后,文件以只读方式打开并与 $InFile 变量相关联。while循环每次将一行读入到 $Op 中。然后,通过预先计划将 expr 映射到 $Op 变量来构造整个 Tcl 命令。然后,扩展,求值,从而分配结果。最后,在 stdout 上显示每步操作和结果。
虽然该样本演示了相对琐细的 eval 应用程序,但从概念上讲,可以根据已知语法的输入文件的输入,很容易地将它扩展为动态文件和/或目录处理,或扩展为对文件类型、许可权、访问时间或任何种类的可测试元素的基本操作。