| 天龙八部私服首页 | 天龙八部世界家族列表 | 天龙八部技术文章 | 精美截图 | 心情故事 |
Tcl语言的一些资料 Tcl语言的一些资料
Tcl是一种很通用的脚本语言,它几乎在所有的平台上都可以解释运行,功能强大。是tool command language的缩写,发音为 "tickle”, 实际上包含了两个部分:一个语言和一个库。 首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一 些互交程序如文本编辑器、调试器和shell。它有一个简单的语法 和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。 其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充(定义新的 过程)的库函数。应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读取(按钮或菜单等)。 但Tcl库收到命令后将它分解并执行内建的命令,经常会产生递归的调用。 在下面的清单中,将会发现第一个很常见的示例程序,它是用 Tcl 实现的。这是一个完整的脚本:第一行命令调用 tclsh 环境,第二行命令执行实际工作。用您所选择的文本编辑器创建该脚本,输入 chmod +x hello.tcl 使之成为可执行文件,然后执行它以测试您这件“作品”。
~/tcltk$ ./hello.tcl
Tcl/Tk 是一种解释型环境。可以通过添加预编译的 C 函数来扩展 Tcl 解释器,可从 Tcl 环境内部调用 Tcl 解释器。可以为特定目的或一般的以及广泛使用的而定制这些扩展。我们将在教程的后面看一些扩展并着重看一下第一个扩展 — 非常流行的 Expect。 在接下来的几屏中,将回顾 Tcl 语言的一些主要特性,从元字符和全局变量到运算符、数学函数以及核心命令。毕竟,这些命令使 Tcl/Tk 成为有特色的,逐步发展的语言。请记住,在本教程中没有篇幅涉及每条命令。这里只突出一部分,以后您可以更进一步了解 Tcl/Tk。 puts stdout "Hello, World! \a" set Pints 6 puts stdout "The answer to the universe is [eval $Pints * $Days]!\n" ***
元字符是在 Tcl/Tk 环境的上下文中有特殊含意的字符或字符对,它们包括分组语句、封装字符串、终止语句以及其它,如下表所示。左边列出的代码中演示了一些元字符。要注意的一个特殊特性是,当使用花括号(防止替代和扩展)代替双引号时,输出中的差异。
puts stdout "Hello, World! \a" set Pints 6 puts stdout "The answer to the universe is [eval $Pints * $Days]!\n" *** 字符 用作
if {$argc >= 1} { *** ~/tcltk$ ./hello3.tcl ring Tcl 全局变量和反斜杠替代 当 Tcl/Tk 脚本开始运行时,存在几个全局变量(如果在当前环境中为非空,则是预先定义的)。这些变量允许如下对操作系统进行访问:argc 是对脚本自变量的计数,而不是对调用的名称进行计数。 argv 是自变量的列表(不是数组)。argv0 是调用的文件名(可以是符号链接)。env 是根据当前外壳的环境变量名建立下标的数组。errorCode 存储有关最近的 Tcl 错误信息,errorInfo 包含对这同一个错误事件的堆栈跟踪。该列表还有另外 12 个 tcl_xxx 变量,从 tcl_interactive 到 tcl_version。可以在 Tcl/Tk in a Nutshell 中找到好的总结,(有关更多信息,请参阅本教程末尾的“参考资料”)。 在左边的样本代码中,使用了其中几个变量以及(又一次)使用了一些反斜杠引用的字符(\n 和 \a)。 \ char 允许替代非打印 ASCII 字符。这对于 UNIX 下的许多脚本语言和外壳环境都是常见的。如表中说明的那样,对于没有定义替代的反斜杠引用的字符只被简单地回送到输出。 \字符 替代
set PI [expr 2 * asin(1.0)] if {$argc == 3} { set Dist [expr sqrt(($X*$X)+($Y*$Y))] puts stdout "Distance = $Dist" } else { ******** Tcl 支持一组标准的运算符和数学函数。这些运算符包括算术、位和逻辑运算符,可以通过 expr 命令使用常规的运算符优先次序规则进行求值。另外,考虑到 Tcl 的实质是面向字符串的脚本语言,所以对一些数学函数进行了合理的补充:
左边这个示例使用了其中一些运算符和函数来计算指定点到原点之间的距离,并返回给定半径的圆的周长和面积。另外,在这个示例中,使用列表下标(lindex)命令来访问 $argv 的个别元素。
foreach Arg $argv { set LineCount 0 Tcl 中的循环命令是 while、for 和 foreach。条件(转移)命令是 if/then/else/elsif 和 switch。上述命令的限定语句是 break、continue、return 和 error。最后,catch 命令提供了错误处理能力。 if/then/else/elsif 已在前面几屏中演示过。在正式语法中会用到 then,但通常会省略掉它。 在左边这个示例中,foreach 结构给 switch 命令提供命令行自变量。当处理自变量时(注意:不正确的输入会终止脚本,因为还没有实现处理错误的 catch),while 循环通过为每一行调用过程并同时对行计数器加 1 来处理输入。代码段结束时,返回处理的行数。 TCL语言(五) Tcl 字符串和模式匹配 ~/tcltk$ tclsh % string toupper $Phrase % string totitle $Phrase % string match ello $Phrase % string match *ello* $Phrase % string length $Phrase % append Phrase "Nice day, eh?" % string toupper $Phrase % string wordend $Phrase 7 表示信息的 string 命令是 length 和 bytelength(可以有所不同,这取决于字符集)。返回布尔值(1 或 0)的比较是 compare、equal 和 match。这里的模式匹配是由“文件名替换”(简单类型的匹配通常与外壳操作相关)完成。还可以通过独特的 regex 和 regsub 命令来使用“高级正规表达式”。 在 Tcl 中执行 index、last、first、wordend 和 wordstart 命令可以实现下标功能。字符串修改是由 tolower、toupper、totitle、trim、trimleft、trimright、replace 和 map 来处理的。后者需要预先定义一个字符映射表。用 range 抽取子字符串,用 repeat 多次输出字符串。 可以使用 append 命令,将文本添加到现有变量中。通过使用与 C 语言的 printf 命令相同的样式和约定,format 命令可用来生成输出字符串。scan 对字符串进行解析并将值赋值给变量。最后,从 Tcl 8.0 开始,用 binary format 和 binary scan 命令添加了将二进制数据作为字符串处理的功能(因而能够处理空字符,而不会失败)。 TCL语言(六) % set c2 [list Ted Alice] % set Party1 [list $c1 $c2] % set Party2 [concat $c1 $c2] % linsert $Party1 1 Richard % 列表在 Tcl 中有两个主要用途。我们已经在通过 foreach 命令(在 Tcl 中的循环和分支中找到)处理命令行自变量的环境中看到第一个用途。第二个用途是动态地构建 Tcl 命令的元素,可以在本教程后面看到使用 eval 命令来执行这种用途。 list 命令接受它的所有自变量并将它们返回在一个列表环境中。自变量可以是值或变量。在左边这个示例中,可以手工创建列表,或可将其它列表视作自变量来使用列表(从而保存第一个“Party”的两对方向)。或者,concat 命令用于将两个或多个列表合并到顶级项的单个实体,返回第二个更有趣的“Party”。 其它一些有用的列表命令及其语法是: llength $List — 返回顶级项的计数结果。 其余列表命令还包括 lreplace、lsearch 和 lsort。split 命令将字符串作为输入并生成经过正确解析的列表,并且在指定的字符处断开字符串。join 执行相反操作,接受列表元素并将它们串在一起,用 joinstring 分隔它们。 TCL语言(六) Tcl 数组 ~/tcltk$ tclsh 正如一般的变量一样,使用 set 命令初始化数组,如左边所示。圆括号内是给出的下标部分。请注意,圆括号不象花括号或双引号那样提供分组。一旦初始化为数组,就不能将变量作为单一变量来访问。如左边列表底部所示,数组元素也可以是列表。 更多 Tcl 数组
虽然设计之初 Tcl 数组是一维的,但有一个模拟多维结构的好方法。因为下标是任意字符串,所以二维数组可以声明如下:
set array($i,$j) 3.14159
TCL语言(七) set PI [expr 2 * asin(1.0)] proc circum { proc c_area { set rad 3 puts stdout "Area of circle ofradius $rad is [c_area $rad],\nthe circumference is[circum $rad].\n" ********* proc 命令定义 Tcl 过程。一旦定义后,就可以象内置的 Tcl 命令那样调用或使用它。另外,可以用缺省值定义这些参数;例如,将左边的定义更改为读取 proc c_area { {rad 1} } 。这将调用没有参数的 c_area 过程,并返回单位圆的面积。 所使用的 rename 命令正如它的字面含意一样,为现有命令或过程提供新名称。使用 rename 有两个明显的原因。第一个原因是,通过重命名原有过程,然后用相同名称的过程替换它,来给现有命令添加功能。过程可以调用原过程,必要时可以添加一些需要的功能。使用 rename 的第二个原因是,映射一个不存在的命令,例如,象 rename exec {}; 一样,可以防止用户执行外部命令。 变量作用域规则
upvar 命令提供将局部变量与另一个作用域中变量的值相关联的设施。这允许根据名称将变量调用进过程,这对于当过程需要可以修改在另一个作用域的值而不仅仅使用它时,就显得非常方便。这个命令语法是 upvar level $VarName LocalVar ,其中 level 是到当前作用域之外的步骤数。“#0”表示全局作用域这一层。 TCL语言(八) proc UserAdd { Acct rName eMail phone } { if {[info exists uData($Acct,rname)]} { puts stdout [UserAdd bpb Brian bilbrey@junk.com 555-1212] puts stdout [UserAdd tom Tom tom@junk.com 555-1212] puts stdout [UserAdd bpb Brian bilbrey@junk.com 555-1212] ****** 除简单的多维数组以外,通常建议用已专门用于过程接口的数组来实现 Tcl 数据结构。从结构的使用者角度来看,虽然这种设计隐藏了具体实现细节,但提供了执行重要的错误检查能力。 左边这个示例中,在将 uData 声明为全局变量后,代码执行检查,以查看帐户是否已经不存在。如果存在,则过程返回(非零)错误消息。这个返回可以用于切换到生成错误文本输出。对于本例,我们简单地提供三个连续输入,其中包括一次重复输入。这会产生如示例底部所示的输出,“1”表示由于一个重复的帐户名称而引起的一个错误返回,这是我们有意这样做的。 其它可能的数据结构包括数组列表、已链接或双重链接的数组或其中的各种排列。因为 Tcl 8.0 所具有的列表重实现提供了不变的访问次数,所以数组列表结构相当有效。 TCL语言(九) 在它扮演的“工具控制语言”角色中,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语言(十) Tcl 进程和文件 I/O Name: orbdesigns.com % set d [date] % set d [exec date] ****** % if [catch {open foo r} Chan] { 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 用于动态脚本 ~/tcltk$ tclsh 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 应用程序,但从概念上讲,可以根据已知语法的输入文件的输入,很容易地将它扩展为动态文件和/或目录处理,或扩展为对文件类型、许可权、访问时间或任何种类的可测试元素的基本操作。
|
天龙八部私服版权所有2006-2008 www.1775jh.com 天龙私服