1、TCL培训教程(全)TCL培训教程(全) 修订记录日期 修订版本 描述 作者2001-02-20 第2页,共58页TCL培训教程(全) 目 录1引言. 62语法. 72.1脚本、命令和单词符号. 72.2置换(substitution) . 72.2.1变量置换(variable subtitution) 82.2.2命令置换(command substitution) 82.2.3反斜杠置换(backslash substitution) . 82.2.4双引号和花括号. 92.3注释. 93变量103.1简单变量103.2数组113.3相关命令113.3.1set . 113.3.2uns
2、et . 113.3.3append和incr . 124表达式124.1操作数124.2运算符和优先级. 124.3数学函数135List . 145.1list命令145.2concat命令: 5.3lindex命令5.4llength命令5.5linsert命令5.6lreplace命令: 5.7lrange命令: 5.8lappend命令: 5.9lsearch命令: 5.10lsort命令: 5.11split命令: 5.12join命令. 14. 14. 15. 1515. 151516. 16. 16176控制流176.1if命令. 176.2循环命令:while、for、 fo
3、reach . 176.2.1while 命令176.2.2for命令. 186.2.3foreach命令186.2.4break和continue命令196.2.5switch 命令. 196.1eval命令. 192001-02-20 第3页,共58页TCL培训教程(全) 6.2source命令. 197过程(procedure) 207.1过程定义和返回值. 207.2局部变量和全局变量207.3缺省参数和可变个数参数217.4引用:upvar 218字符串操作. 228.1format 命令. 228.2scan命令. 238.3regexp命令. 238.4regsub命令. 258
4、.5string命令258.5.1string compare ?-nocase? ?-length int? string1 string2 . 258.5.2string equal ?-nocase? ?-length int? string1 string2 258.5.3string first string1 string2 ?startindex? 258.5.4string index string charIndex 268.5.5string last string1 string2 ?startindex? . 268.5.6string length string .
5、268.5.7string match ?-nocase? pattern string . 268.5.8string range string first last . 278.5.9string repeat string count . 278.5.10string replace string first last ?newstring? 278.5.11string tolower string ?first? ?last? . 278.5.12string toupper string ?first? ?last? . 278.5.13 string trim string ?c
6、hars? . 278.5.14string trimleft string ?chars? . 278.5.15string trimright string ?chars? 279文件访问. 289.1文件名289.2基本文件输入输出命令289.3随机文件访问. 299.4当前工作目录309.5文件操作和获取文件信息3010错误和异常3310.1错误. 3310.2从TCL脚本中产生错误. 3410.3使用catch捕获错误3510.4其他异常. 3511深入TCL 3711.1查询数组中的元素3711.2 info命令3811.2.1变量信息. 3811.2.2过程信息. 3911.2.
7、3命令信息. 4011.2.4 TCL的版本和库. 412001-02-20 第4页,共58页TCL培训教程(全) 11.2.5 命令的执行时间. 4111.2.6 跟踪变量4111.2.7命令的重命名和删除4311.2.8 unknown 命令4411.2.9自动加载. 4412历史记录4513TCL和CC+ . 4713.1生成自己的TCLSH 4813.2扩展自己的命令:方法(一) 4813.2.1编写扩展命令对应的C/C+过程4813.2.2注册命令. 4913.2.3命令返回值和命令对应的过程的返回值5013.3扩展自己的命令:方法(二) 5213.3.1Tcl_Obj 结构. 52
8、13.3.2编写扩展命令对应的C/C+过程5413.3.3注册命令. 5413.4利用clientData参数和deleteProc参数5513.5在C/C+应用程序中嵌入TCL 5814总结. 592001-02-20 第5页,共58页TCL培训教程(全) TCL培训教程(全)1 引言TCL(Tool Command Language) 是一种解释执行的脚本语言(Scripting Language)。它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。由于TCL的解释器是用一个CC+语言的过程库实现的,因此在某种意义上我们又可以把TCL看作一个
9、C库,这个库中有丰富的用于扩展TCL命令的CC+过程和函数,可以很容易就在CC+应用程序中嵌入TCL,而且每个应用程序都可以根据自己的需要对TCL语言进行扩展。我们可以针对某一特定应用领域对TCL语言的核心命令集进行扩展,加入适合于自己的应用领域的扩展命令,如果需要,甚至可以加入新的控制结构,TCL解释器将把扩展命令和扩展控制结构与固有命令和固有控制结构同等看待。扩展后的TCL语言将可以继承TCL 核心部分的所有功能,包括核心命令、控制结构、数据类型、对过程的支持等。根据需要,我们甚至可以屏蔽掉TCL的某些固有命令和固有控制结构。通过对TCL的扩展、继承或屏蔽,用户用不着象平时定义一种计算机语
10、言那样对词法、语法、语义、语用等各方面加以定义,就可以方便的为自己的应用领域提供一种功能完备的脚本语言。TCL良好的可扩展性使得它能很好地适应产品测试的需要,测试任务常常会由于设计和需求的改变而迅速改变,往往让测试人员疲于应付。利用TCL的可扩展性,测试人员就可以迅速继承多种新技术,并针对产品新特点迅速推出扩展TCL命令集,以用于产品的测试中,可以较容易跟上设计需求的变化。另外,因为TCL是一种比CC+ 语言有着更高抽象层次的语言,使用TCL可以在一种更高的层次上编写程序,它屏蔽掉了编写CC+程序时必须涉及到的一些较为烦琐的细节,可以大大地提高开发测试例的速度。而且,使用TCL语言写的测试例脚
11、本,即使作了修改,也用不着重新编译就可以调用TCL解释器直接执行。可以省却不少时间。TCL 目前已成为自动测试中事实上的标准。2 语法简单的讲,TCL语言的语法实际上是一些TCL解释器怎样对TCL命令进行分析的规则的集合。2.1 脚本、命令和单词符号一个TCL脚本可以包含一个或多个命令。命令之间必须用换行符或分号隔开,下面的两个脚本都是合法的:set a 1 set b 2 2001-02-20 第6页,共58页TCL培训教程(全) 或set a 1;set b 2 TCL的每一个命令包含一个或几个单词,第一个单词代表命令名,另外的单词则是这个命令的参数,单词之间必须用空格或TAB键隔开。TC
12、L解释器对一个命令的求值过程分为两部分:分析和执行。在分析阶段,TCL 解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,TCL 解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C+过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。2.2 置换(substitution) 注:在下面的所有章节的例子中, 为TCL的命令提示符,输入命令回车后,TCL会在接着的一行输出命令执行结果。 / 后面是我自己加上的说明,不是例子的一部分。TCL解释器在分析命令时,把所有的命令参数都当作字符串看待
13、,例如:%set x 10 /定义变量x,并把x的值赋为10 10 %set y x+100 /y的值是x+100,而不是我们期望的110 x+100 上例的第二个命令中,x被看作字符串x+100的一部分,如果我们想使用x的值10 ,就必须告诉TCL解释器:我们在这里期望的是变量x的值,而非字符x 。怎么告诉TCL解释器呢,这就要用到TCL语言中提供的置换功能。TCL提供三种形式的置换:变量置换、命令置换和反斜杠置换。每种置换都会导致一个或多个单词本身被其他的值所代替。置换可以发生在包括命令名在内的每一个单词中,而且置换可以嵌套。2.2.1 变量置换(variable subtitution)
14、 变量置换由一个符号标记,变量置换会导致变量的值插入一个单词中。例如:%set y $x+100 /y的值是10+100,这里x被置换成它的值10 10100 这时,y的值还不是我们想要的值110,而是10+100,因为TCL解释器把10+100看成是一个字符串而不是表达式,y要想得到值110,还必须用命令置换,使得TCL会把10+100看成一个表达式并求值。2.2.2 命令置换(command substitution) 命令置换是由括起来的TCL命令及其参数,命令置换会导致某一个命令的所有或部分单词被另一个命令的结果所代替。例如:%set y expr $x+100 110 y的值是110
15、,这里当TCL解释器遇到字符 时,它就会把随后的expr作为一个命令名,从而激活与expr对应的C/C+过程,并把 expr 和变量置换后得到的 10+110 传递给该命令过程进行处理。2001-02-20 第7页,共58页TCL培训教程(全) 如果在上例中我们去掉,那么TCL会报错。因为在正常情况下,TCL解释器只把命令行中的第一个单词作为看作命令,其他的单词都作为普通字符串处理,看作是命令的参数。注意,中必须是一个合法的TCL脚本,长度不限。中脚本的值为最后一个命令的返回值,例如:%set y expr $x+100;set b 300 /y的值为300,因为set b 300的返回值为3
16、00 300 有了命令置换,实际上就表示命令之间是可以嵌套的,即一个命令的结果可以作为别的命令的参数。2.2.3 反斜杠置换(backslash substitution) TCL语言中的反斜杠置换类似于C语言中反斜杠的用法,主要用于在单词符号中插入诸如换行符、空格、$等被TCL解释器当作特殊符号对待的字符。例如:set msg multiple space /msg 的值为multiple space 。如果没有 的话,TCL会报错,因为解释器会把这里最后两个单词之间的空格认为是分隔符,于是发现set 命令有多于两个参数,从而报错。加入了 后,空格不被当作分隔符, multiple spac
17、e 被认为是一个单词(word) 。又例如:%set msg money $3333 nArray a2 /这个命令的执行结果为:money $3333Array a2 这里的$不再被当作变量置换符。TCL支持以下的反斜杠置换: Backslash Sequence Replaced By a Audible alert (0x7) b Backspace (0x8) f Form feed (0xc) n Newline (0xa) r Carriage return (0xd) t Tab (0x9) v Vertical tab (0xb) ddd Octal value given b
18、y ddd (one, two, or three ds) xhh Hex value given by hh (any number of hs) newline space A single space character. 例如:set a x48 /对应 xhh H /十六进制的48正好是72,对应H set a 110 /对应 ddd H /八进制的110正好是72,对应H 2001-02-20 第8页,共58页5 TCL培训教程(全) set a expr / 对应newline space,一个命令可以用newline转到下一行继续2+32.2.4 双引号和花括号除了使用反斜杠外
19、,TCL提供另外两种方法来使得解释器把分隔符和置换符等特殊字符当作普通字符,而不作特殊处理,这就要使用双引号和花括号()。TCL解释器对双引号中的各种分隔符将不作处理,但是对换行符及和两种置换符会照常处理。例如:%set x 100 100 %set y “$x ddd“ 100 ddd 而在花括号中,所有特殊字符都将成为普通字符,失去其特殊意义,TCL解释器不会对其作特殊处理。%set y /n$x expr 10+100 /n$x expr 10+100 2.3 注释TCL中的注释符是 , 和直到所在行结尾的所有字符都被TCL看作注释,TCL解释器对注释将不作任何处理。不过,要注意的是,
20、必须出现在TCL解释器期望命令的第一个字符出现的地方,才被当作注释。例如:%This is a comment %set a 100 # Not a comment wrong # args: should be “set varName ?newValue?“ %set b 101 ; # this is a comment 101 第二行中 就不被当作注释符,因为它出现在命令的中间,TCL解释器把它和后面的字符当作命令的参数处理,从而导致错误。而第四行的 就被作为注释,因为前一个命令已经用一个分号结束,TCL解释器期望下一个命令接着出现。现在在这个位置出现# ,随后的字符就被当作注释了。3
21、 变量TCL支持两种类型的变量:简单变量和数组。3.1 简单变量一个TCL的简单变量包含两个部分:名字和值。名字和值都可以是任意字符串。例如一个名为“1323 7set b 4 4 6.2 source命令source命令读一个文件并把这个文件的内容作为一个脚本进行求值。例如:source e:/tcl&c/hello.tcl 注意路径的描述应该和UNIX相同,使用/ 而不是 。7 过程(procedure) TCL支持过程的定义和调用,在TCL中,过程可以看作是用TCL脚本实现的命令,效果与TCL的固有命令相似。我们可以在任何时候使用proc命令定义自己的过程,TCL中的过程类似于C中的函数
22、。7.1 过程定义和返回值TCL中过程是由proc命令产生的:例如:% proc add x y expr $x+$y proc命令的第一个参数是你要定义的过程的名字,第二个参数是过程的参数列表,参数之间用空格隔开,第三个参数是一个TCL脚本,代表过程体。 proc生成一个新的命令,可以象固有命令一样调用:% add 1 2 32001-02-20 第19页,共58页TCL培训教程(全) 在定义过程时,你可以利用return命令在任何地方返回你想要的值。 return命令迅速中断过程,并把它的参数作为过程的结果。例如:% proc abs x if $x = 0 return $x retur
23、n expr -$x 过程的返回值是过程体中最后执行的那条命令的返回值。7.2 局部变量和全局变量对于在过程中定义的变量,因为它们只能在过程中被访问,并且当过程退出时会被自动删除,所以称为局部变量;在所有过程之外定义的变量我们称之为全局变量。TCL中,局部变量和全局变量可以同名,两者的作用域的交集为空:局部变量的作用域是它所在的过程的内部;全局变量的作用域则不包括所有过程的内部。这一点和C语言有很大的不同. 如果我们想在过程内部引用一个全局变量的值,可以使用global命令。例如:% set a 4 4 % proc sample x global a incr a return expr $
24、a+$x % sample 3 8 %set a 5 全局变量a在过程中被访问。在过程中对a的改变会直接反映到全局上。如果去掉语句global a, TCL会出错,因为它不认识变量a. 7.3 缺省参数和可变个数参数TCL还提供三种特殊的参数形式:首先,你可以定义一个没有参数的过程,例如:proc add expr 2+3 其次,可以定义具有缺省参数值的过程,我们可以为过程的部分或全部参数提供缺省值,如果调用过程时未提供那些参数的值,那么过程会自动使用缺省值赋给相应的参数。和CC+中具有缺省参数值的函数一样,有缺省值的参数只能位于参数列表的后部,即在第一个具有缺省值的参数后面的所有参数,都只能
25、是具有缺省值的参数。例如:proc add val1 val2 2 val3 3 expr $val1+$val2+$val32001-02-20 第20页,共58页TCL培训教程(全) 则:add 1 /值为6 add 2 20 /值为25 add 4 5 6 /值为15 另外,TCL的过程定义还支持可变个数的参数,如果过程的最后一个参数是args, 那么就表示这个过程支持可变个数的参数调用。调用时,位于args以前的参数象普通参数一样处理,但任何附加的参数都需要在过程体中作特殊处理,过程的局部变量args将会被设置为一个列表,其元素就是所有附加的变量。如果没有附加的变量,args就设置成一
26、个空串,下面是一个例子:proc add val1 args set sum $val1foreach i $args incr sum $ireturn $sum则:add 2 /值为2add 2 3 4 5 6 /值为207.4 引用:upvar 命令语法:upvar ?level? otherVar myVar ?otherVar myVar .? upvar命令使得用户可以在过程中对全局变量或其他过程中的局部变量进行访问。 upvar命令的第一个参数otherVar 是我们希望以引用方式访问的参数的名字,第二个参数myVar 是这个过程中的局部变量的名字,一旦使用了upvar 命令把o
27、therVar 和myVar 绑定,那么在过程中对局部变量myVar 的读写就相当于对这个过程的调用者中otherVar 所代表的局部变量的读写。下面是一个例子:% proc temp arg upvar $arg bset b expr $b+2% proc myexp var set a 4temp areturn expr $var+$a 则:% myexp 7 132001-02-20 第21页,共58页TCL培训教程(全) 这个例子中,upvar 把$arg(实际上是过程myexp 中的变量a)和过程temp 中的变量b绑定,对b的读写就相当于对a的读写。upvar命令语法中的lev
28、el参数表示:调用upvar命令的过程相对于我们希望引用的变量myVar 在调用栈中相对位置。例如:upvar 2 other x 这个命令使得当前过程的调用者的调用者中的变量other,可以在当前过程中利用x访问。缺省情况下,level的值为1,即当前过程(上例中的temp) 的调用者(上例中的myexp) 中的变量(上例中myexp 的a)可以在当前过程中利用局部变量(上例中temp 的b)访问。如果要访问全局变量可以这样写:upvar 0 other x 那么,不管当前过程处于调用栈中的什么位置,都可以在当前过程中利用x访问全局变量other。8 字符串操作因为TCL把所有的输入都当作字
29、符串看待,所以TCL提供了较强的字符串操作功能,TCL中与字符串操作有关的命令有:string、format 、regexp、regsub、scan等。8.1 format 命令语法:format formatstring ?vlue value.? format 命令类似于ANSIC中的sprintf函数和MFC中CString类提供的Format 成员函数。它按formatstring 提供的格式,把各个value的值组合到formatstring 中形成一个新字符串,并返回。例如:%set name john John %set age 20 20 %set msg format “ %
30、s is %d years old” $name $age john is 20 years old 8.2 scan命令语法:scan string format varName ?varName .? scan命令可以认为是format 命令的逆,其功能类似于ANSI C中的sscanf函数。它按format 提供的格式分析string字符串,然后把结果存到变量varName 中,注意除了空格和TAB键之外,string 和format 中的字符和% 必须匹配。例如:% scan “some 26 34“ “some %d %d“ a b 2 % set a 26 % set b 2001
31、-02-20 第22页,共58页TCL培训教程(全) 34 % scan “12.34.56.78“ “%d.%d.%d.%d“ c d e f 4 % puts format “the value of c is %d,d is %d,e is %d ,f is %d“ $c $d $e $f the value of c is 12,d is 34,e is 56 ,f is 78 scan命令的返回值是匹配的变量个数。而且,我们发现,如果变量varName 不存在的话,TCL会自动声明该变量。8.3 regexp命令语法:regexp ?switchs? ?-? exp string ?
32、matchVar? ?subMatchVar subMatchVar.? regexp命令用于判断正规表达式exp是否全部或部分匹配字符串string,匹配返回1,否则0。在正规表达式中,一些字符具有特殊的含义,下表一一列出,并给予了解释。字符 意义. 匹配任意单个字符 表示从头进行匹配$ 表示从末尾进行匹配x 匹配字符x,这可以抑制字符x的含义chars 匹配字符集合chars中给出的任意字符,如果chars中的第一个字符是,表示匹配任意不在chars中的字符,chars的表示方法支持a-z之类的表示。(regexp) 把regexp作为一个单项进行匹配* 对*前面的项0进行次或多次匹配+
33、对前面的项进行1次或多次匹配? 对?前面的项进行0次或1次匹配regexp1|regexp2 匹配regexp1或regexp2中的一项下面的一个例子是从Tcl and Tk ToolKit 中摘下来的,下面进行说明:(0x)?0-9a-fA-F+|0-9+)$这个正规表达式匹配任何十六进制或十进制的整数。两个正规表达式以|分开(0x)?0-9a-fA-F+和0-9+,表示可以匹配其中的任何一个,事实上前者匹配十六进制,后者匹配的十进制。表示必须从头进行匹配,从而上述正规表达式不匹配jk12之类不是以0x或数字开头的串。表示必须从末尾开始匹配,从而上述正规表达式不匹配12jk之类不是数字或a-
34、fA-F结尾的串。下面以(0x)?0-9a-fA-F+ 进行说明,(0x)表示0x一起作为一项,?表示前一项(0x)可以出现0次或多次,0-9a-fA-F表示可以是任意0到9之间的单个数字或a到f或A到F之间的单个字母,表示象前面那样的单个数字或字母可以重复出现一次或多次。2001-02-20 第23页,共58页TCL培训教程(全) % regexp (0x)?0-9a-fA-F+|0-9+)$ ab 1 % regexp (0x)?0-9a-fA-F+|0-9+)$ 0xabcd 1 % regexp (0x)?0-9a-fA-F+|0-9+)$ 12345 1 % regexp (0x)?
35、0-9a-fA-F+|0-9+)$ 123j 0 如果regexp命令后面有参数matchVar 和subMatchVar,则所有的参数被当作变量名,如果变量不存在,就会被生成。 regexp把匹配整个正规表达式的子字符串赋给第一个变量,匹配正规表达式的最左边的子表达式的子字符串赋给第二个变量,依次类推,例如:% regexp (0-9+) *(a-z+) “ there is 100 apples“ total num word 1 % puts “ $total ,$num,$word“100 apples ,100,apples regexp可以设置一些开关(switchs,来控制匹配结
36、果:-nocase 匹配时不考虑大小写-indices 改变各个变量的值,这是各个变量的值变成了对应的匹配子串在整个字符串中所处位置的索引。例如:% regexp -indices (0-9+) *(a-z+) “ there is 100 apples“ total num word 1 % puts “ $total ,$num,$word“9 20 ,10 12,15 20 正好子串“ 100 apples”的序号是9-20,” 100” 的序号是10-12,” apples” 的序号是15-20 - 表示这后面再没有开关(switchs了,即使后面有以- 开头的参数也被当作正规表达式的
37、一部分。8.4 regsub命令语法:regsub ?switchs? exp string subSpec varname regsub的第一个参数是一个整个表达式,第二个参数是一个输入字符串,这一点和regexp命令完全一样,也是当匹配时返回1,否则返回0。不过regsub用第三个参数的值来替换字符串string中和正规表达式匹配的部分,第四个参数被认为是一个变量,替换后的字符串存入这个变量中。例如:% regsub there “They live there lives “ their x 1 % puts $x They live their lives 这里there被用their
38、替换了。regsub命令也有几个开关(switchs): 2001-02-20 第24页,共58页TCL培训教程(全) -nocase 意义同regexp命令中。-all 没有这个开关时,regsub只替换第一个匹配,有了这个开关,regsub将把所有匹配的地方全部替换。- 意义同regexp命令中。8.5 string 命令string命令的语法:string option arg ?arg.? string命令具有强大的操作字符串的功能,其中的option选项多达20个。下面介绍其中常用的部分。8.5.1 string compare ?-nocase? ?-length int? str
39、ing1 string2 把字符串string1和string2进行比较,返回值为-1、0或1,分别对应string1小于、等于或大于string2。如果有 -length 参数,那么只比较前 int 个字符,如果 int为负数,那么这个参数被忽略。如果有 -nocase参数,那么比较时不区分大小写。8.5.2 string equal ?-nocase? ?-length int? string1 string2 把字符串string1和string2进行比较,如果两者相同,返回值为1,否则返回0。其他参数与8.5.1同。8.5.3 string first string1 string2
40、?startindex? 在string2 中从头查找与string1匹配的字符序列,如果找到,那么就返回匹配的第一个字母所在的位置(0-based)。如果没有找到,那么返回-1。如果给出了startindex变量,那么将从startindex处开始查找。例如:% string first ab defabc 3 % string first ab defabc 4 -1 8.5.4 string index string charIndex 返回string 中第charIndex个字符(0-based)。charIndex可以是下面的值:整数n: 字符串中第n个字符(0-based)end
41、 : 最后一个字符end整数n:倒数第n个字符。string index “abcd“ end-1 返回字符c 如果charIndex小于0,或者大于字符串string的长度,那么返回空。例如:% string index abcdef 2c% string index abcdef end-2d8.5.5 string last string1 string2 ?startindex? 2001-02-20 第25页,共58页TCL培训教程(全) 参照8.5.3.唯一的区别是从后往前查找8.5.6 string length string 返回字符串string的长度. 8.5.7 stri
42、ng match ?-nocase? pattern string 如果pattern 匹配string,那么返回1,否则返回0.如果有-nocase参数,那么就不区分大小写. 在pattern 中可以使用通配符: * 匹配string中的任意长的任意字符串,包括空字符串. ? 匹配string中任意单个字符chars 匹配字符集合chars中给出的任意字符,其中可以使用 A-Z这种形式x 匹配单个字符x,使用是为了让x可以为字符*,-,. 例子: % string match * abcdef 1 % string match a* abcdef 1 string match a?cdef
43、abcdef 1 % string match ab-fcdef abcdef /注意一定药用, 否则TCL解释器会把b-f当作命令名1 /从而导致错误% string match ab-fcdef accdef 1 8.5.8 string range string first last 返回字符串string中从第first个到第last个字符的子字符串(0-based)。如果first “ def 8.5.14string trimleft string ?chars? 同8.5.13。不过只删除左边的字符。8.5.15string trimright string ?chars? 同8
44、.5.13。不过只删除右边的字符。9 文件访问TCL提供了丰富的文件操作的命令。通过这些命令你可以对文件名进行操作(查找匹配某一模式的文件)、以顺序或随机方式读写文件、检索系统保留的文件信息(如最后访问时间)。9.1 文件名TCL中文件名和我们熟悉的windows 表示文件的方法有一些区别:在表示文件的目录结构时它使用/ ,而不是 ,这和TCL最初是在UNIX下实现有关。比如C盘tcl目录下的文件sample.tcl 在TCL中这样表示:C:/tcl/sample.tcl 。9.2 基本文件输入输出命令这个名为tgrep的过程,可以说明TCL文件I/O的基本特点:proc tgrep patt
45、ern filename set f open $filename r while gets $f line if regexp $pattern $line puts stdout $lineclose $f 2001-02-20 第27页,共58页TCL培训教程(全) 以上过程非常象UNIX的grep命令,你可以用两个参数调用它,一个是模式,另一个是文件名,tgrep将打印出文件中所有匹配该模式的行。下面介绍上述过程中用到的几个基本的文件输入输出命令。open name ?access? open命令以access方式打开文件name 。返回供其他命令(gets,close等)使用的文件标
46、识。如果name 的第一个字符是“|”,管道命令被触发,而不是打开文件。文件的打开方式和我们熟悉的C语言类似,有以下方式:r 只读方式打开。文件必须已经存在。这是默认方式。r+ 读写方式打开,文件必须已经存在。w 只写方式打开文件,如果文件存在则清空文件内容,否则创建一新的空文件。w+ 读写方式打开文件,如文件存在则清空文件内容,否则创建新的空文件。a 只写方式打开文件,文件必须存在,并把指针指向文件尾。a+ 只读方式打开文件,并把指针指向文件尾。如文件不存在,创建新的空文件。open命令返回一个字符串用于表识打开的文件。当调用别的命令(如:gets,puts,close,对打开的文件进行操作
47、时,就可以使用这个文件标识符。TCL有三个特定的文件标识: stdin,stdout和stderr ,分别对应标准输入、标准输出和错误通道,任何时候你都可以使用这三个文件标识。gets fileId ?varName? 读fileId 标识的文件的下一行,忽略换行符。如果命令中有varName就把该行赋给它,并返回该行的字符数(文件尾返回-1),如果没有varName参数,返回文件的下一行作为命令结果(如果到了文件尾,就返回空字符串)。和gets类似的命令是read,不过read不是以行为单位的,它有两种形式:read ?-nonewline? fileId 读并返回fileId 标识的文件中
48、所有剩下的字节。如果没有nonewline 开关,则在换行符处停止。read fileId numBytes 在fileId标识的文件中读并返回下一个numbytes 字节。puts ?-nonewline? ?fileId? string puts 命令把string写到fileId中,如果没有nonewline 开关的话,添加换行符。fileId默认是stdout。命令返回值为一空字符串。puts命令使用C的标准I/O库的缓冲区方案,这就意味着使用puts产生的信息不会立即出现在目标文件中。如果你想使数据立即出现在文件中,那你就调用flush命令:flush fileId 把缓冲区内容写到fileId标识的文件中,命令返回值为空字符串。flush命令迫使缓冲区数据写到文件中。flush直到数据被写完才返回。当文件关闭时缓冲区数据会自动flush。close ?fileId? 关闭标识为fileId的文件,命令返回值为一空字符串。2001-02-20 第28页,共58页TCL培训教程(全) 这里特别说明的一点是,TCL中对串口、管道、socket等的操作和对文件的操作类似,以上对文件的操作命令同样适用于它们。9.3 随机文件访问默认文件输入输出方