第一部分:TCL基本知识
一.简介
Tcl 表示工具命令语言(Tool Command Language),它是一种流行的脚本编制语言,最初由加州大学伯克利分校的 John Ousterhout 教授开发。John Ousterhout 打算将 Tcl 作为一种将其它程序组件粘合在一起的语言,既可以以同其它脚本语言相同的方式将 Tcl 用作交互式 shell/脚本解释器,也可以将其作为脚本解释器嵌入您自己的 C 应用程序。在这种方式下,它就变成了一种向您自己的程序中添加脚本编制控制的方法,并且它提供了一些接口,这些接口允许您用自己的以 C 语言实现的脚本命令扩展基本 Tcl 语言.
Tcl 还有各种扩展,诸如 Tk,UI 工具箱,以及 Expect,Expect 是一种扩展,用于自动化同其它基于 shell 的命令(例如 telnet 和 ftp)的交互。
Tcl是一种很通用的脚本语言,它几乎在所有的平台上都可以解释运行,功能强大。
Tcl包含了两个部分:一个语言和一个库。
首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一 些互交程序如文本编辑器、调试器和shell。它有一个简单的语法 和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。
其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充(定义新的 过程)的库函数。应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读取(按钮或菜单等)。 但Tcl库收到命令后将它分解并执行内建的命令,经常会产生递归的调用。
脚本语言的优势:
快速开发:脚本语言极大地简化了“开发、部署、测试和调试”的周期过程。
容易部署:大多数脚本语言都能够随时部署,而不需要耗时的编译/打包过程。
同已有技术的集成:脚本语言被Java或者COM这样的组件技术所包围,因此能够有效地利用代码。
易学易用:很多脚本语言的技术要求通常要低一些,因此能够更容易地找到大量合适的技术人员。
动态代码:脚本语言的代码能够被实时生成和执行,这是一项高级特性,在某些应用程序里(例如JavaScript里的动态类型)是很有用也是必需的。
二.TCL的语法规则
1.解释器
在Tcl的数据结构中的核心是Tcl_Interp.一个解释器包含了一套命令,一组变量和一些用于描述状态的东西。每一个 Tcl命令是在特定的Tcl_Interp中运行的,基于Tcl的应用程序可以同时拥有几个Tcl_Interp。Tcl_Interp是一个轻量级的结构,可以快速的新建和删除。
2.数据类型
Tcl只支持一种数据结构:字符串(string)。所有的命令,命令的所有的参数,命令的结果,所有的变量都是字符串。请牢记这一点,所有的东西都是字符串。 这是它比较有特点的方面字符串有三种形式:命令(command), 表达式(expresion)和表(list)。
三.TCL基本语法
1.tcl命令
一条tcl命令的基本语法为:
command arg1 arg2 arg3
其中command可以是内建过程也可以是用户建的新命令,如果是用户用户建的新命令应用程序中用函数Tcl_CreateCommand来创建。所有的参数作为字符串来传递,命令自己会按其所需来解释的参数的。命令的名字必须被打全,但 Tcl解释器找不到一同名的命令时会用 unknown命令来代替。;
空格符用来分隔命令名和他的变元,换行符或者分号用来表示一条命令的结束.
例如:
set a 22 //相当于C中的 a=22 a是一个变量这条命令分为三个域:1: set 2: a 3: 22
set使用于设置变量的值的命令,a、20 作为参数来传给它,a使它要操作的变量名,22是要付给的a值。
2.注释
和shell很象,第一个字母是"#"的Tcl字符串是注释。
3.变量
set命令用于将值赋给变量.它接受2个变元:第一个是变量名,第2个是值.变量名可任意长,并且可区分大小写;
在使用变量前无须对tcl变量进行声明;
可以通过美元符号语法来获取变量的值.
4.数字表达式
tcl解释器本身不对数学表达式进行计算,tcl只是完成分组,替换和命令的调用工作,而expr命令用来对数字表达式进行分析和计算.
5.替换和分组
5.1 在变量里面提到过的使用$符合来完成替换
5.2命令替换
当命令的一个子域以方括号开始以方括号结束,表示要进行一个命令子替换。并执行该子命令,用其结果来替换原命令中的方括号部分。方括号中的部分都被视为Tcl命令。
例如:
set a [set b "hello"]
实现执行 set b "hello" 并用其结果来替换源命令 中的方括号部分,产生一条新命令
set a "hello" //"hello" 为 set b "hello" 的返回值
最终的结果是b="hello" a="hello"
方括号没有分组作用
5.3反斜杠替换
用来引用对解释器来说具有特殊意义的字符,比如:你可以通过反斜杠引用形式指定一个纯粹的美元符合,花括号或者方括号.
如:set dollar /$foo
=>$foo
5.4 使用花括号和双引号进行分组
双引号和花括号被用来将多个单词组织成一个变元.双引号和花括号之间的差别就是,双引号允许在分组重出现替换操作,而花括号则会阻止这种替换的发生.这种规则适用于命令,变量和反斜杠替换.
如:set s hello
=>Hello
puts stdout "The length of $s is [string length $s]"
=>The length of Hello is 5
puts stdout {The length of $s is [string length $s]}
=>The length of $s is [string length $s]
5.5 分组在替换前进行
TCL语法分析器只对命令执行一遍分组和字符串替换操作.分组决定是在替换前完成的,这是TCL的一种很重要的属性,它表明经过替换的值并不影响分组结果,因为分组决定已经作出了.
例如:
set x 7;set y 9
puts student $s+$y=[expr $x+$y]
=>7+9=16
四.总结
一. 命令综述
1.一个命令就是一个字符串(string)。
2.命令是用换行符或分号来分隔的。
3.一个命令由许多的域组成。第一个于是命令名,其它的域作为参数来传递。
4.域通常是有空白(Tab横向制表健 Space空格)来分开的。
5.双引号可以使一个参数包括换行符或分号。三种子替换仍然发生。
6.花括号类似于双引号,只是不进行三总体换。
7.系统只进行一层子替换,机制替换的结果不会再去做子替换。而且子替换可以在任何一个域进行。
8.如果第一个非控字符是`#", 这一行的所有东西都是注释。
二.替换和分组
下面的规则总结了TCL解释器在调用一条命令之前所完成的基本分组和替换机制:
命令变元以空白符加以分隔,除非他们像下面所描述的这样使用花括号或者双引号进行分组.
使用花括号,{},进行分组会阻止替换操作.括号可以嵌套.解释器将会在分组中包括所有匹配左右括号之间的字符,其中包括换行符、分号和嵌套括号.用于分组的花括号(即,最外层的花括号)不包含在分组值中.
使用双引号,””,进行分组允许替换操作.解释器会将所有的内容包括在内,直到碰到另一个双引号为止,其中包括换行符和分号.分组用的双引号不包括在分组字符当中.可以通过反斜杠引用(如/”)将双引号包括在分组中.
分组决定是在替换之前作出的.这也意味着变量值或者命令结果并不影响分组.
美元符号,$,将会导致变量替换.变量名可以任意长,而且区分大小写.如果变量引用嵌套在其他字符串中,或是其中包含了除字母、数字和下划线之外的其他字符,那么可以通过${varname}的语法形式加以区分.
方括号,[],将会导致命令替换.括号中的内容都被当作一条命令看待,而且包括方括号在内的所有内容都将替换成命令的结果.这是嵌套是允许的.
反斜杠字符,/,用来引用特殊的字符.你可以认为这是另外一种形式的替换,这里反斜杠与后面的一个或一组字符将被替换成一个新字符.
替换操作可以发生在任何地方,除非使用花括号加以阻止.分组中的一部分可以是常量字符串,而别的部分又可以是替换所产生的结果,甚至命令名都可以受到替换的影响.
在调用命令之前只完成一遍替换,不再对替换结果进行第2遍解释.这条规则在你的变量值或命令结果中包含诸如空格、美元符合、方括号或花括号等特殊字符时就显得非常重要.因为子进行一遍替换操作,所有你不必担心这些值中得特殊字符会导致额外得替换.
三.使用FAQ
一种常见的错误就是在使用花括号或双引号进行分组时忘记在变元之间插入空格符.因为空白符用作变元的分隔符,而花括号和引号只提供分组的功能.如果你忘记了这些空格符,就会出现”在封闭花括号或者双引号之后发现非期望字符”之类的错误.由于}与{直接缺少空格,所有下面的代码就是错误的:
if {$x > 1}{puts “x=$x”}
双引号只有在空白符之后出现时才被用于分组,这也就是说你可以将双引号包含在一个分组当中而无须使用反斜杠引用.这要求要有花括号或空白符来界定这个分组.不推荐使用这种晦涩难懂的功能
当使用双引号进行分组时,花括号的特殊作用将被关闭.替换会在双引号扩起来的分组中的任何地方发生.下一条命令中,变量仍然被替换了
如:set x xvalue;set y “foo {$x} bar”;
=> foo {xvalue} bar
当使用双引号进行分组时,其中的内嵌命令仍然可以使用双引号进行分组.
put “result [format “%f %f” $x $y]”
用做命令替换的方括号之间的空白符不是必须的.出于分组的考虑,解释器会把方括号之间的任何内容都作为当前分组的一部分.下面的代码将x设置为两条命令结果的连接,原因就是]和[之间没有空格.
set x [cmd1][cmd2]
当使用花括号或双引号进行分组时,换行苻和分号可以被忽略.他们会像其他字符一样包括在分组字符中.下面的代码将x设置为包含换行符的字符串:
set x “this is line one”
this is line two.
this is line three.
在进行命令替换过程中,换行符与分号的作用就是作为命令终止符.如果你有一条很长的嵌套在方括号中的命令,而且想在另一行上继续这条命令的话,就请在换行符前插入一个反斜杠.这在例1-9中已有示范.
当一个美元符号后面跟的是除字母、数字、下划线或左小括号之外的其他内容时,它就会被当作一个纯粹的美元符号.
第二部分:JACL介绍
一.Jacl简介:
Jacl 是流行的 Tcl 脚本语言的 Java 实现。使用 Jacl,您可以在 XML 或 XSL 中嵌入用脚本编写的功能。此外,由于其 Java 扩展,因此,您可以使用 Jacl 来同基于 Java 的 Apache 工具内的 Java 对象进行交互
Jacl 向 Java 开发人员提供了另外一种处理 XML 的方法。Jacl 是流行的脚本语言 Tcl 的一种 Java 实现,使用它您可以深入底层并向使用 Ant 编写的 XML 构建或使用 Xalan 和 Cocoon 生成的转换中添加功能。
除了实现大多数 Tcl 命令集之外,Jacl 还提供了一些其自己的 Tcl 命令,这些命令允许程序员同 Java VM 交互。这些额外的命令允许 Jacl 代码创建 Java 对象,调用其中的方法,调用静态方法,内省 Java 对象甚至将 Jacl 侦听器绑定到 Java 事件。这种在同一个脚本中同时使用 Tcl 和 Java 代码的能力带来了许多可能性。试想为系统编写一套 Java 服务、组件或构件块。通过在同这些组件相同的 VM 中使用 Jacl,您可以以脚本方式执行和控制 Java 组件。
您也可以使用 Jacl 作为交互式 shell,在那里您可以以交互方式(也就是从通常的 shell 提示符中)创建 Java 对象并调用其中的方法
Jacl 是 Tcl 解释器的 Java 实现:无须安装 Tcl 解释器,您仅需一个 Java VM 以及相关的 Jacl jar 文件。Jacl 通过其 Java 特性提供了一种真正的跨平台的脚本语言
对于习惯了 Java 而又不想投入太多时间学习另外一种语言的程序员来说,Jacl 也是一种非常强大的通用脚本语言。Tcl 有相对清晰和简单的语法,Java 程序员可以以混合然后匹配的方式使用 Jacl:将 Jacl 用于那些脚本语言最适用的地方(简单文件处理、正则表达式解析、字符串替换、执行系统命令等等),并利用 Jacl 的 Java 扩展来访问完整的 Java API 以及重用现有的 API 知识。
二.Jacl安装
下载 jacl1.2.6 源代码压缩文档,解压缩/压缩/tar 该分发版,然后执行 README 中的构建指令。一旦配置并构建了 jacl,您将在平台构建目录内发现两个 jar 文件,jacl.jar 和 tcljava.jar。要在 UNIX 平台上运行交互式 Jacl shell,请运行 UNIX 平台构建目录下的 jaclsh。如果您运行的是 Windows,请使用清单 2 中的批处理文件。
您的环境必须将 jaclsh 文件的位置包含在其 PATH 里,并将两个 jar 文件包含在 CLASSPATH 里。(您甚至想要将 jaclsh 复制或符号链接到 /usr/local/bin。)
现在可以使用 Jacl 了
第三部分.TCL内建函数对字符串的处理
这部分主要描述有关字符串操作和简单模式匹配的内容.主要介绍的命令有:
1. string
2. append
3. format
4. scan
5. binary
字符串是tcl中的基本数据项,因此有大量用来操作字符串的命令并不奇怪.一个与之密切相关的主题就是模式匹配,其中通过将字符串与模式进行匹配可以是字符串的比较功能更强大.
一.string命令:
string命令实际上是一组操作字符串的命令,string的第一个变元决定了进行什么样的操作,如下面的例子计算得到一个变量值的长度:
set name “brent welch”
string length $name
=> 11
常用的字符串操作有
equal操作
用法为:string equal?-nocase?str1 str2
字符串match
用法为:string match pattern str
大小写转换操作
tolower 、totitle及toupper.用法为:string tolower string ?first?last?
字符串清理操作
trim、trimright和trimleft.用法为:string trim string ?chars?
将string分裂成列表。缺省以空白为分隔符,也可通过splitChars来设定分隔符
split string ?splitChars?
执行字符串的比较,按 C strcmp 的方式。返回 -1, 0, or 1。
string compare string1 string2
在string1种查找string2的定义次出现的位置。未找到返回-1
string first string1 string2
返回字符串string的长度
string length string
判断string是否能匹配pattern。pattern是以shell文件名的统配格式来给出
string match pattern string
返回字符串string中从first到last之间的内容
string range string first last
将string转换为小写
string tolower string
将string转换为大写
string toupper string
将string的左右空白去掉
string trim string
将string的左空白去掉
string trimleft string
将string的右空白去掉
string trimright string
FAQ:
使用expr来进行字符串匹配不可靠,建议不要使用,安全的比对方法为使用string compare和equal操作来进行字符串比对
string is命令用来测试一个字符串是否属于某个特定的类.
srting map命令根据字符映射对字符串进行转换,映射以输入、输出形式表示.
例如:sring map “food” {f p d 1}
=>pool
二.append命令
append varName value
append varName value value value ...
append命令接收一个变量名作为它的第一个变元,并把剩余的变元连接到该指定变量当前值的后面.这个变量如果事先不存在就会被创建
FAQ:
对于大字符串来说,addend命令很有效率
例如:
append i "some new stuff" 就比下面的方式速度快
set i " some new stuff "
三.format命令
format命令与C语言中的printf函数类似,它根据一种格式说明来格式化字符串:
format spec value1 value2....
spec变元包括文字和关键词.文字将原封不动地存在到结果中,而每个关键字会指示如何格式化对应的变元.使用百分号(%)来引入一个关键字,其后跟着0个或多个修饰符并使用一个转换限定符作为结尾.关键字的例子包括用于浮点数的%f、用于整数的%d以及用于字符串格式的%s.使用%%可以获取一个单一的百分号.对于每个变元来说,最为通用的关键字说明可以包括多达6个部分:
位置说明符
标志
字段宽度
精度
单词长度
转换字符
四.scan命令
scan命令根据格式规范描述来解析一个字符串并把值赋给变量.它返回成功完成的转换格式.该命令的通用形式为:
scan string format var ?var? ?var?....
scan中的格式几乎与format命令中的完全相同.不存在扫描格式%u.描述格式%c会将一个字符转换成它的十进制值.
scan格式包含有一种集合的概念.它使用方括号来界定一组字符.这个集合匹配拷贝到变量中的一个或多个字符.它使用横杠来指定一个区间.下面的例子扫描一个全部以小写字母组成的字段
scan abcABC {%[a-z]} result
=>1
set result
=> abc
五.binary命令
binary命令用于字符串和压缩的二进制表示形式之间的转换.binary format命令接收数值并根据模板进行压缩.例如:她可以用来在内存中格式化一个适合传递给fortran的浮点向量.最终的二进制值被返回:
binary format template value ?value...?
binary scan命令根据类似的模板从二进制字符串中获取数值.这对获取以二进制格式存储的数据来说非常有用.它将值赋给一组TCL变量
binary scan value template variable ?variable ...?
第四部分.TCL列表
这部分主要描述有关TCL列表的内容.主要介绍的命令有:
list
lindex
llength
lrange
lappend
linsert
lreplace
lsearch
lsort
concat
join
split
TCL列表是一系统的值.当你输出一个列表时,它拥有与TCL命令相同的语法.列表使用空白符将元素分割开来.可以使用花括号或双引号将包含空白符的单词组成一个单一的列表元素
一.list命令
list命令根据它的变元来构建一个列表,因此列表的每个元素都是一个变元.如果某个元素包含有特殊字符,list命令将会添加引用以确保它们被解析为结果列表中的单一元素.
例如:
set x {1 2}
=>1 2
set y foo
=>foo
set L1 [list $x “a b” $y]
=> {1 2} {a b} foo
set L2 “/{$x/} {a b } $y”
=>{1 2} {a b} foo
FAQ
list命令将会自动完成引用,对比上述例子L1和L2.
二.lappend命令
lappend命令用于将元素添加到列表末尾.
例如:
lappend new 1 2
=> 1 2
lappend new 3 “4 5”
=> 1 2 3 {4 5}
set new
=>1 2 3 {4 5}
三concat命令
concat命令适用于将列表拚装到一起.它将变元连接起来,其间用空格分开.这样多个列表会合并成一个列表,每个输入列表中的顶层列表元素会成为结果列表中的顶层列表元素.
例如:
set x {4 5 6}
set y {2 3}
set z 1
concat $z $y $x
=> 1 2 3 4 5 6
FAQ
1. 双引号和concat的区别
对于简单情况,双引号就像concat一样工作.然而,concat命令会先去除其变元末尾的多余空白符,然后才使用一个单一的空格符将他们连接起来
2. concat和list的区别
当冬天建立tcl命令时,list于concat之间的差异就显得重要起来.基本规则就是list和lappend保留列表的结构,而concat(或双引号)则会消除一层列表结构.由于存在list与concat返回相同结果的例子,这种差异就显得很微秒.不幸的是,这样会导致产生依赖于数据的错误.
例子:双引号与concat和list命令的比较
set x {1 2}
=> 1 2
set y “$x 3”
=>1 2 3
set y [concat $x 3]
=> 1 2 3
set s { 2 }
=> 2
set y “1 $s 3”
=> 1 2 3
set y [concat 1 $s 3]
=> 1 2 3
set z [list $x $s 3]
=> {1 2} { 2 } 3
四.获取列表元素
一.llength命令返回列表中元素的个数.
如:llength {a b {c d} “e f g” h}
=>5
llength{ }
=> 0
二.lindex命令返回列表中的一个特定元素.它接收一个索引; 列表的索引从0开始记数.
如:set x {1 2 3 }
lindex $x 1
=> 2
还可以使用关键字end来指定列表的最后一个元素,或是使用语法end-N从列表的末尾倒记数.
三.lrange命令
lrange命令返回一个区段的列表元素.一个一个列表及两个索引为变元,可以使用end和end-N作为索引
五.修改列表
一.linsert命令在列表值中指定的索引位置插入一个元素.如果索引为0或者更小,那么元素就会添加倒列表值的前面.如果索引等于或者大于列表的长度,元素则被追加倒尾部.
二.lreplace命令将一个区段的列表元素替换为新的元素.如果没有指定任何新的元素,那么它就会从列表中删除这些元素.
FAQ
linsert命令和lreplace命令并不对现有报表进行修改,而是返回一个新的列表值.如下面例子
使用linsert和lreplace修改列表
linsert {1 2} 0 new stuff
=> new stuff 1 2
set x [list a {b c} e d]
=> a {b c} e d
lreplace $x 1 2 B C
=> a B C d
lreplace $x 0 0
=> {b c} e d
六.搜索列表
lsearch命令返回列表中的一个值的索引,如果值不在就返回-1
七.对列表进行排序
使用lsort命令以多种方式对列表进行排序.lsort并不是对原表进行排序,而是返回一个新的列表,可以通过-ascii、-directory、-interger或-real选项来指定基本的排序类型,可以通过选项-increasing或-decreasing指定排序方式,默认选项设置为: -ascii –increasing.
例如: lsort –ascii {a Z n2 n100}
=> Z a n100 n2
lsort -dictionary {a Z n2 n100}
=> a n2 n100 Z
八.split命令
split命令接收一个字符串,并根据指定的字符将其分割转换为一个列表,同时保证其结果具有恰当的列表语法.
例如:set line {welch:*:28405:100:Brent Welch:/usr/welch:/bin/csh}
split $line :
=> welch * 28405 100 {Brent Welch} /usr/welch /bin/csh
lindex [split $line :] 4
=> Brent Welch
FAQ
不要对任意数据都使用列表操作
既便你的数据中包含有空格分隔的单词,你也应当对任意的输入数据小心使用列表操作.否则,输入中零散的双引号或者花括号会在脚本中产生无效列表结构和错误.
九.join命令
join命令作用和split正好相反,它接收一个列表值并使用指定的分隔列表元素的字符对其重新进行格式化.
例如:
join {1 {2 3} {4 5 6 }}
=> 1:2 3:4 5 6
第五部分:控制结构命令
TCL中的控制结构是通过使用命令来实现的,这些命令中包括循环命令:while、foreach和for,包括条件命令:if和switch,包括错误处理命令:catch,还包括一些用于微调控制结构的命令:break、continue、return和error.
一.If Then Else控制命令
if expression ?then? body1 ?else? ?body2
例如:
if {$x = = 0}{
puts stderr “divide by zero!”
} else {
set slope [expr $y/$x]
}
FAQ:
花括号的位置非常重要
如if $x break continue 建议改为如下风格:
if { $x } {
break
} else {
continue
}
二.switch控制命令
switch命令根据命令表达式值的不同分别执行多个分支命令体中的一个.该命令的一般形式为:
switch flags value pat1 body1 pat2 body2
可以指定任意数量的模式 – 命令体对.如果匹配多个模式,那么只需要计算第一个匹配模式的命令体,也可以将所有的模式 – 命令体组织倒一个变元中.
switch flags value { pat1 body1 pat2 body2........}
三while控制命令
while命令接收2个变元: 一个测试表达式和一个命令体,如下:
while booleanExpr body
FAQ
while命令反复对布尔表达式进行测试,如果表达式为真(非 0) 就执行命令体.由于在每次循环之前都要重新计算测试表达式的值,因此保护表达式使之免于在while命令被调用以前发生任何替换操作非常关键.下面就是一个无限循环的例子:
set i 0; while $i <10 {incr i}
下面的代码才是正确的
set i 0 ;while {$i<10} {incr i}
四.Foreach命令
Foreach命令循环执行一个命令体,每次将一个或多个列表中的每个值赋值给一个或多个循环变量.该命令的语法如下:
foreach loopVar valueList commandBody
Foreach名字支持多个循环变量.假设有2个循环变量x和y,在第一次循环中,x从值列表中获取第一个值,而y获取第二个值,在第2次循环中,x获取第3个值,而y获取第4个值,这样一直持续到不在有值为止.如果没有足够的可赋给所有循环变量的值,多余的变量将会以空字符串作为它们的值.
Foreach支持多个值列表.Foreach可以同时对多个值列表进行循环操作.在这种情况下,每个值列表还可以包含一个或多个变量.foreach将一直循环执行直到所有值列表中的所有值都被使用过为止.如果在最后一次循环之前就用尽了一个值列表中的值,那么与之对应的循环变量就会以空字符串来作为他们的值.
六.for命令
for命令与c语言中的for语句相似,接收4个变元:
for initial test final body
七.Break与Contiune
可以通过break和contiune命令来控制循环的执行.break命令会导致立刻从循环中退出,而contiune命令则会是循环继续进行下一个迭代,tcl中没有goto命令.
八Catch
在实际应用中,如果一条命令在调用时使用了错误的变元数目或是根据自身的实现检测出了某种错误,它就会报错.一个没有捕获的错误将会终断脚本的执行.catch命令就是用来捕获这种错误的,它接收2个变元:
catch command ?resultVar?
catch的第一个变元是命令体.第2个变元是一个变量名,它包含命令的结果,或是在命令报错时的一条错误信息.如果没有捕获任何错误,catch就会返回0,如果捕获到了错误就返回一个非零的错误代码.
应当使用花括号而不是双引号来将命令括起来,这是因为catch将会调用完整的TCL解释器来解释命令.如果使用双引号,那么在调用catch之前就会发生又一轮的替换操作,最简单的catch用法就像下面这样:
catch {command}
catch命令的捕获不仅仅是错误,如果命令体中包含有return、break或contiune命令的话,它们将会终止命令体并被catch以非0的返回代码反映出来.
九.Error命令
除非使用catch命令进行捕获,否则error命令将会报告一个错误状态并终止脚本的执行,该命令最多可以接收三个变元:
error message
error message info
error message info code
message返回一个错误,引起解释器停止运行。info用于初始化全局变量errorInfo。code被付给errorCode。
十.Return命令
return命令用来从过程中返回,还可以使用return的一些可选变元来指定异常的返回状态,完整语法如下:
return ?code c?-errorinfo i? ?-errorcode ec? string
-code选项是ok、error、return、break、contiune中的一个,也可以是一个整数,如果没有指定-code,默认就是ok
code error选项似的return的行为非常类似与error命令.-errorcode选项设置全局变量errorcode,而-errorinfo选项则初始化全局变量errorinfo.当使用return –code error是,在堆栈状态中就不会有error命令.
第六部分:过程与作用域
过程封装了一组命令并为变量引入了一种局部作用域.
一.proc命令
TCL过程由proc命令来定义,接收三个变元:
proc name params body
第一个变元为过程名,它会增加到tcl解释器所识别的命令集中.过程名区分大小写而且可以包含任意字符,过程名并不与变量名冲突
第二个变元是一个包含参数名的列表.
第三个变元是一个过程体
FAQ
使用rename来改变命令
rename命令用来改变命令的名字.其用途有2个
对现有过程进行扩充,并保留老命令的透明性.
通过更改命令名称可以完全隐藏一条命令.
二.global命令
全局作用域为顶层作用域,该作用域处于任何过程之外,必须通过global命令才能在过程内部使用在全局作用域中定义的变量.global的语法为:
global varName1 varName2......
FAQ:
global命令存在于过程内部.
三upvar命令
当需要将变量名二不是他的值传递给过程的时候,就药使用vpvar命令.upvar命令将一个局部变量与沿Tcl调用栈向上一层作用域中的变量关联在一起.upvar命令语法为:
upvar ?level1? varName localVar
第七部分:TCL数组
一. array命令
array命令返回有关数组变量的信息.
array names命令返回数组中定义的索引名,如果没有定义数组变量,那么array names就会返回一个空列表
array get和array set操作用来在数组和列表间进行转换.array get返回的列表包含偶数个数的元素,第一个元素是索引,下一个是对应的数组值,剩下的列表元素交替为索引和值.array set的列表变元必须要有同样的结构.
array命令参数极其相关的命令参见下面例子:
一组用于向量操作的命令。第二个参数是子命令名
array subcommand arrayName
array subcommand arrayName arg ...
假设:
set a(1) 1111
set a(2) 2222
set a(three) 3333
一下均以它为例子(tclsh在中运行)。
返回一个数组元素名字的列表
array names arrayName
例如:
tclsh>array names a
1 2 three
返回数组的元素个数
array size arrayName
例如:
tclsh>array size a
3
用于遍历的命令
arrry startsearch arrayName
初始化一次遍历,返回一个遍历标示(searchId)在下面的命令是中使用。
返回下一个数组中的元素。如果没有返回一个空串。
array nextelement arrayName searchId
返回 1 表示还有更多的元素。0 表示没有了。
array anymore arrayName searchId
结束该次遍历。
array donesearch arrayName searchId
返回下一个元素。
array nextelement arrayName searchId
例如:
tclsh>array startsearch a
s-1-a
tclsh>array nextelement a s-1-a
1111
tclsh>array nextelement a s-1-a
2222
tclsh>array anymore a s-1-a
1
tclsh?array nextelement a s-1-a
3333
tclsh>array donesearch a s-1-a
注意可以同时并发多个遍历。
第八部分:对文件和程序的操作
一.使用exec运行程序
exec命令从TCL脚本中进行程序
如: set a [expr 1+1]
exec命令支持全套的I/O重定向和管道语法.每个进程通常有三个与之关联的I/O通道:标准输入,标准输出以及标准错误输出.通过I/O重定向,可以是这些I/O通道转向事先有Tcl的open命令打开的文件或I/O通道.管道是这样一个进程链,一个命令的标准输出挂接到管道中另一个命令的标准输入.可以将任意数量的程序连接起来形成管道.
I/O重定向语法的基本思路为: | 代表管道, > 代码输出, < 代表输入,使用&来将标准错误输出合并到标准输出中,使用2>来将标准错误输出单独分离出来.你可以通过使用@来使用自己的I/O通道.
例如: set n [exce sort < /ect/passwd | uniq | wc -1 2> /dev/null]
例子说明如下:使用exec来执行管道中的三个程序.第一个程序是sort.它从文件/etc/passwd中接收输入.sort的输出通过管道发送给uniq,它消除所有重复的行.uniq的输出又通过管道发送给wc,由它来计算出相应的行数.将命令的错误输出转送到空设备以抑制任何错误信息.
二.file命令
file名字提供了几种检测文件系统中文件状态的方法.
常用的file方法介绍:
使用file join来构造文件名
使用file split对文件名进行分段
使用file copy对文件进行拷贝
file copy ?-force? file1 file2
使用file mkdir创建目录
file mkdir dir dir....
使用file delete删除文件
file detete ?-force? name name.....
使用file rename重新命名文件和目录
file rename ?-force? old new
返回文件的最近存取时间
file atime name
返回name所描述的文件名的目录部分
file dirname name
回文件是否可被执行
file executable name
返回文件是否存在,返回1表示存在,0表示文件不存在。
file exists name
返回文件的扩展名
file extension name
判断是否为目录
file isdirectory name
判断是否为文件
file isfile name
以数组形式返回。执行lstat系统函数。存储在varName
file lstat name varName
文件的最近修改时间
file mtime name
判断文件是否属于你
file owned name
判断文件是否可读。
file readable name
读出符号连接的真正的文件名
file readlink name
返回不包括最后一个点的字符串
file rootname name
返回文件的大小
file size name
调用stat内和调用,以数组形式存在varName中
file stat name varName
返回最后一个斜线以后的部分
file tail name
返回文件类型file, directory, characterSpecial, blockSpecial, fifo, link, 或socket
file type name
判断文件是否可写
file writable name
三.对I/O命令的总结
打开文件进行I/.O操作
open命令建立一个指向文件或进程管道的I/O通道,open返回值为I/O通道标识符.可以将这个结果保存在变量中并像使用stdout,stdin和stderr等标识符那样来使用这个变量.基本语法为:
open what ?access? ?permissions?
what变元要么是一个文件名,要么就是一个类似于exec命令所使用的管道描述.
access变元有两种形式,即可以是一种于fopen函数库兼容的短字符序列,也可以是一个包含posix存取标志的列表.
读写操作
puts命令向输出通道写入一个字符串和一个换行符.它接收一个用来阻止通常要追加到输出通道中的换行符的-nonewline变元
语法为:puts ?-nonewline? ?channel? string
gets命令读取一行输入,而且有两种形式.只带有一个变元的,gets返回从指定I/O通道中读取的行.;带有第2个变元varname,gets就将行内容存储到命令的变量中并返回读取的字节数.
语法为:gets channel ?varname?
read命令成功读取数据
语法为:read channel ?numBytes?
read -nonewline channel
read有2种形式,可以指定-nonewline变元或numBytes变元,但不能同时指定2个变元.不带numBytes,它就会读取并返回整个文件.给的一个字节记数变元,read就会返回那个数据的信息.
随机读取I/O
seek命令和tell命令提供了对I/O通道的随机存取
关闭I/O通道
close命令释放与I/O通道关联的操作系统资源
exit和pid命令
exit命令用来终止脚本的执行.
pid命令返回当前进程的进程ID.
第九部分:如何利用tcl和jacl编写测试脚本