Tcl语言参考.docx
《Tcl语言参考.docx》由会员分享,可在线阅读,更多相关《Tcl语言参考.docx(11页珍藏版)》请在冰豆网上搜索。
Tcl语言参考
Tcl语言参考
Tcl("ToolCommandLanguage",即工具命令语言;Tcl念作"tickle"即“踢叩” )是一种简单易用易于扩展的嵌入式脚本语言,主要用于发布命令给交互式程序(如文本编辑器、调试器),及完成自动化批处理工作。
Tcl语言不同于其他语言的最大的特点是:
Tcl程序由Tcl命令序列组成,其每条语句都是一条指令。
由于其极易扩展的特性,Tcl有大量的用C/C++编写的扩展用于提供Tcl本身不具有的功能。
其中使用最广泛的扩展是TK,TK提供了各种OS平台下的图形用户界面GUI(连强大的Python语言都不单独提供自己的GUI,而是提供接口适配到TK上)。
另一个流行的扩展包是Expect,它提供了通过终端自动执行命令的能力,例如passwd,ftp,telnet等命令驱动的外壳。
一、Tcl程序基本结构
1、基本语法
Tcl的语法类似于shell:
一条Tcl的命令串包含若干条命令,命令使用换行符或分号来隔开;而每一条命令包含若干个域(field),域使用空白(空格或TAB)来隔开——第一个域是命令的名字,其它的域是该命令的参数。
Tcl解释器对一个命令的执行过程分为两步:
分析阶段和执行阶段。
在分析阶段,Tcl解释器运用规则识别出命令并把命令分成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,Tcl解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有后面的单词作为参数传递给该命令过程,让命令过程进行处理。
Tcl解释器既可以执行Tcl内建命令亦可执行用户自己通过C/C++函数实现的新建命令,在应用程序中可用函数Tcl_CreateCommand来完成命令的创建。
所有命令参数都被作为字符串来传递,命令自己会按其所需来解释参数。
另外关于Tcl的注释有一个特殊的要求:
'#'必须出现在Tcl解释器期望命令的第一个字符出现的地方,才被当作注释。
例如:
seta100 #Notacomment
setb101; #thisisacomment
第一个例子中'#'及其后面的内容会被当作set的参数而非注释从而导致参数个数错误;但第二个被解释为注释,因为'#'前面有一个分号,而分号和换行一样被看作是命令的分隔符。
2、置换(Substitution)
setx10
sety100+x
上面命令执行后,y的值是“100+x”而不是我们期望的110。
这是因为Tcl解释器在分析命令时,把所有的命令参数都当作字符串看待,所以x被看作了字符串“100+x”的一部分。
如果我们想使用x的值'10',就必须告诉Tcl解释器:
我们在这里期望的是变量x的值,而非字符'x'。
那么怎么告诉Tcl解释器呢?
这就要用到Tcl语言中的置换功能。
Tcl提供三种形式的置换:
变量置换、命令置换和反斜杠置换。
每种置换都会导致一个或多个单词本身被其他的值所代替。
置换可以发生在包括命令名在内的每一个单词中,而且置换可以嵌套。
(1)变量置换(variablesubstitution)
变量置换由一个$符号标记,变量置换会导致变量的值而非变量(标识符)本身被插入到字符串中。
setx10
sety100+$x
这时,y的值还不是我们想要的值110,而是10+100,因为Tcl解释器把10+100看成是一个字符串而不是表达式;y要想得到值110,还必须用命令置换,使得Tcl会把10+100看成一个表达式并求值。
(2)命令置换(commandsubstitution)
命令置换是由[]括起来的Tcl命令及其参数,命令置换会导致某一个命令的所有或部分单词(参数)被另一个命令的结果所代替。
setx10
sety[expr100+$x]
这时,y的值就是110了。
这里当Tcl解释器遇到字符'['时,它就会把随后的expr作为一个命令名,从而激活与expr对应的C/C++过程,并把expr命令中变量置换后得到的'10+110'传递给该命令过程进行处理。
有了命令置换,实际上就表示命令之间是可以嵌套的,即一个命令的结果可以作为别的命令的参数。
注意,[]中必须是一个合法的Tcl脚本,长度不限。
[]中脚本的值为最后一个命令的返回值。
(3)反斜杠置换(backslashsubtitution)
Tcl语言中的反斜杠置换类似于C语言中反斜杠的用法,主要用于在单词符号中插入诸如换行符、空格、[、$等被Tcl解释器当作特殊符号对待的字符。
例如:
setmsgmultiple\space
如果没有'\'的话,Tcl会报错,因为解释器会把这里最后两个单词之间的空格认为是分隔符,于是发现set命令有多于两个参数,从而报错。
加入了'\'后,空格不被当作分隔符,'multiplespace'被认为是一个单词(word)。
(4)双引号和花括号
除了使用反斜杠外,Tcl提供另外两种方法来使得解释器把分隔符和置换符等特殊字符当作普通字符,而不作特殊处理,这就要使用双引号和花括号({})。
Tcl解释器对双引号中的各种分隔符将不作处理,但是对换行符及$和[]两种置换符会照常处理。
而在花括号中,所有特殊字符都将成为普通字符,失去其特殊意义,Tcl解释器不会对其作特殊处理。
二、Tcl变量数据类型
Tcl只支持一种数据类型:
字符串(string)。
所有的命令,命令的所有的参数,命令的结果,所有的变量都是字符串。
请牢记这一点,所有的东西都是字符串(然而字符串的实际解释是依赖于其所处上下文,共有三种解释:
命令,表达式和表)。
(1)简单变量
一个Tcl的简单变量包含两个部分:
名字和值,其中名字和值都可以是任意字符串。
不过为了更好的使用变量置换功能,变量名最好按C\C++语言中标识符的命名规则命名。
这是因为Tcl解释器在分析一个变量置换时,只把从$符号往后直到第一个不是字母、数字或下划线的字符之间的单词符号作为要被置换的变量的名字。
例如:
seta2
seta.15
setb$a.1
在最后一个命令行,我们希望把变量a.1的值付给b,但是Tcl解释器在分析时只把$符号之后直到第一个不是字母、数字或下划线的字符(这里是'.')之间的单词符号(这里是'a')当作要被置换的变量的名字,所以Tcl解释器把a置换成2,然后把字符串“2.1”付给变量b。
这显然与我们的初衷不同。
当然,如果变量名中有不是字母、数字或下划线的字符又要用变量置换,可以用花括号把变量名括起来。
例如:
setb${a.1}
(2)数组变量
数组是一些元素的集合。
Tcl的数组和一般编程语言中的数组有很大的区别。
在Tcl中,不能单独声明一个数组,数组只能和数组元素一起声明。
数组中数组元素的名字包含两部分:
数组名和数组中元素的名字,Tcl中数组元素的名字(下标〕可以为任何字符串。
例如:
setday(monday)1
setday(sunday) 2
(3)string结构及其操作
因为TCL把所有的输入都当作字符串看待,所以TCL提供了较强的字符串操作功能
【format】
语法:
formatformatstringvluevalue...
format命令类似于ANSIC中的sprintf函数,它按formatstring提供的格式,把各个value的值组合到forma-tstring中形成一个新字符串并返回。
例如:
setmsg[format"%sis%dyearsold"$name$age]
【scan】
语法:
scanstringformatstingvarNamevarName...
scan命令可以认为是format命令的逆,其功能类似于ANSIC中的sscanf函数。
它按formatsting提供的格式分析string字符串,然后把结果存到变量varName中,注意除了空格和TAB键之外,string和formatsting中的字符和'%'必须匹配。
例如:
scan"some2634""some%d%d"ab
【regexp】
语法:
regexp[switchs][--]expstring[matchVar]\[subMatchVarsubMatchVar...]
regexp命令用于判断正规表达式exp是否全部或部分匹配字符串string,匹配返回1,否则0。
regexp可以设置一些开关(switchs〕,来控制匹配的具体方式,如:
-nocase,-line等,其中--表示这后面再没有开关(switchs〕了,即使后面有以'-'开头的参数也被当作正规表达式的一部分。
如果regexp命令后面有参数matchVar和subMatchVar,则所有的参数被当作变量名,如果变量不存在,就会被生成。
regexp把匹配整个正规表达式的子字符串赋给第一个变量,匹配正规表达式的最左边的子表达式的子字符串赋给第二个变量,依次类推,例如:
regexp{([0-9]+)*([a-z]+)}"thereis100apples"totalnumword
puts"$total,$num,$word"
显示结果为:
100apples,100,apples
【regsub】
语法:
regsub[switchs]expstringsubSpecvarname
regsub的第一个参数是一个正则表达式,第二个参数是一个输入字符串,这一点和regexp命令完全一样,也是当匹配时返回1,否则返回0。
不过regsub用第三个参数的值来替换字符串string中和正规表达式匹配的部分,第四个参数被认为是一个变量,替换后的字符串存入这个变量中。
例如:
regsubthere"Theylivetherelives"theirx
puts$x
显示结果为:
Theylivetheirlives
【sting】
语法:
stringsubcmdarg[arg...]
string命令具有强大的操作字符串的功能,并通过其中的subcmd来区别具体想要执行的具体操作。
他们中的一些如下:
stringlengthstring
stringrangestringfirstlast
stringindexstringcharIndex
stringtolowerstring[first][last]
stringreplacestringfirstlast[newstring]
stringequal[-nocase][-lengthint]string1string2
stringmatch[-nocase]patternstring 如果pattern匹配string,那么返回1,否则返回0.
stringcompare[-nocase][-lengthint]string1string2 如果有-length参数,那么只比较前int个字符
stringfirststring1string2[startindex]在string2中从头查找与string1匹配的字符序列,如果找到,那么就返回匹配的第一个字母所在的位置(0-based)。
如果没有找到,那么返回-1。
stringtrimstring[chars] 返回值为:
从string字符串的首尾删除掉了字符集合chars中的字符后的字符串。
如果没有给出chars,那么将删除掉spaces、tabs、newlines、carriagereturns这些字符.
(4)list结构及其操作
list这个概念在TCL中是用来表示集合的。
TCL中list是由一堆元素组成的有序集合,list可以嵌套定义,list每个元素可以是任意字符串,也可以是list。
Tcl提供了很多基本命令对list进行操作。
【list】
语法:
list[valuevalue...]
这个命令生成一个list,list的元素就是所有的value。
【concat】
语法:
concatlist[list...]
这个命令把多个list合成一个list。
【llength】
语法:
llengthlist
返回list的元素个数。
【lindex】
语法:
lindexlistindex
返回list的第index个(0-based)元素。
【lrange】
语法:
lrangelistfirstlast
返回list的第first(0-based)到第last(0-based)元素组成的串,如果last的值是end。
就是从第first个直到串的最后。
【linsert】
语法:
linsertlistindexvalue[value...?
]
返回一个新串,新串是把所有的value参数值插入list的第index个(0-based)元素之前得到。
【lappend】
语法:
lappendvarnamevalue[value...?
]
把每个value的值作为一个元素附加到变量varname后面,并返回变量的新值,如果varname不存在,就生成这个变量。
【lreplace】
语法:
lreplacelistfirstlast[valuevalue...]
返回一个新串,新串是把list的第firs(0-based)t到第last个(0-based)元素用所有的value参数替换得到的。
如果没有value参数,就表示删除第first到第last个元素。
【lsort】
语法:
lsort[options?
]list
这个命令返回把list排序后的串。
options可以是如下值:
-ascii按ASCII字符的顺序排序比较.这是缺省情况。
-dictionary按字典排序,与-ascii不同的地方是:
(1)不考虑大小写
(2)如果元素中有数字的话,数字被当作整数来排序.
【lsearch】
语法:
lsearch[-option] listpattern
返回list中第一个匹配模式pattern的元素的索引,如果找不到匹配就返回-1。
option取-exact、-glob、-regexp是三种模式匹配的技术,缺省时使用-glob匹配。
【join】
语法:
joinlist[joinString]
这个命令把list的所有元素合并到一个字符串中,中间以joinString分开。
缺省的joinString是空格。
【split】
语法:
splitstring[splitChars]
把字符串string按分隔符splitChars分成一个个单词,返回由这些单词组成的串。
如果splitChars是一个空字符{},string被按字符分开。
如果splitChars没有给出,以空格为分隔符。
(5)file结构及其操作
TCL提供了丰富的文件操作的命令。
通过这些命令你可以对文件名进行操作(查找匹配某一模式的文件)、以顺序或随机方式读写文件、检索系统保留的文件信息(如最后访问时间)。
<1>基本文件I/O
pwd和UNIX下的pwd命令完全一样,没有参数,返回当前目录的完整路径。
cd命令也和UNIX命令也一样,使用一个参数,可以把工作目录改变为参数提供的目录。
以下这个名为tgrep的过程,可以说明TCL文件I/O的基本特点:
proctgrep{patternfilename}{
setf[open$filenamer]
while{[gets$fline]}{
if{[regexp$pattern$line]}{
putsstdout$line
}
}
close$f
}
open命令返回一个字符串用于表识打开的文件。
当调用别的命令(如:
gets,puts,close,〕对打开的文件进行操作时,就可以使用这个文件标识符。
TCL有三个特定的文件标识:
stdin,stdout和stderr,分别对应标准输入、标准输出和错误通道,任何时候你都可以使用这三个文件标识。
<2>随即文件访问
默认文件输入输出方式是连续的:
即每个gets或read命令返回的是上次gets或read访问位置后面的字节,每个puts命令写数据是接着上次puts写的位置接着写。
TCL提供了seek,tell和eof等命令使用户可以非连续访问文件。
每个打开的打开文件都有访问点,即下次读写开始的位置。
文件打开时,访问点总是被设置为文件的开头或结尾,这取决于打开文件时使用的访问模式。
每次读写后访问位置按访问的字节数后移相应的位数。
seekfileIdoffset[origin]把fileId标识的文件的访问点设置为相对于origin偏移量为offset的位置。
origin可以是start,current,end,默认是start。
tellfileId返回fileId标识的文件的当前访问位置。
eoffileId如果到达fileId标识的文件的末尾返回1,否则返回0。
<3>文件操作和获取文件信息
【grob】
语法:
glob[switches]pattern[pattern...]
glob命令的模式采用stringmatch命令的匹配规则,返回匹配这个(些)模式的所有文件的列表。
例如:
glob*.c*.h
glob*/只返回当前目录的所有子目录。
【file】
语法:
filesubcmdarg[arg...]
file通过众多的subcmd子操作提供强大的文件操作和访问能力。
他们中的一些如下:
fileexistsname
fileextensionname
filemkdirdir[dir...]
filecopy[-force][--]sourcetarget
filerename[-force][--]sourcetarget
filedelete[-force][--]pathname[pathname...]
三、Tcl表达式
(1)操作数
Tcl表达式的操作数通常是整数或实数。
整数一般是十进制的,但如果整数前两个字符是0x则这个整数被看作是十六进制的。
Tcl的实数的写法与ANSIC中完全一样。
(2)运算符
Tcl中的运算符的语法形式和用法跟ANSIC中完全一致。
另外,Tcl中提供了大量的常用数学函数来增强自身的数学运算和处理能力,这些函数的形式和用法大都与ANSIC中的数学函数完全一致。
四、Tcl流程控制
TCL中的控制流和C语言类似,包括if、switch、for、while、foreach、break、continue等命令。
(1)条件语句
if{$x>0}{
.....
}elseif{$x==1}{
.....
}elseif{$x==2}{
....
}else{
.....
}
注意,上例中'{'一定要写在上一行,因为如果不这样,TCL解释器会认为if命令在换行符处已结束,下一行会被当成新的命令,从而导致错误的结果。
在Tcl的其他流程控制命令的书写中也要注意这个问题。
书写中还要注意的一个问题是if和{之间应该有一个空格,否则TCL解释器会把'if{'作为一个整体当作一个命令名,从而导致错误。
switch[option]$x{
a-
b{incrt1}
c{incrt2}
default{incrt3}
}
其中可选参数option,表示进行匹配的方式。
TCL支持三种匹配方式:
-exact方式,-glob方式,-regexp方式,缺省情况表示-glob方式。
-exact方式表示的是精确匹配,-glob方式的匹配方式和stringmatch命令的匹配方式相同,-regexp方式是正规表达式匹配方式。
条件中a的后面跟一个'-'表示使用和下一个模式相同的脚本,default表示匹配任意值。
一旦switch命令找到一个模式匹配,就执行相应的脚本,并返回脚本的值作为switch命令的返回值。
(2)循环语句
forinittestreinitbody
参数init是一个初始化脚本,第二个参数test是一个表达式,用来决定循环什么时候中断,第三个参数reinit是一个重新初始化的脚本,第四个参数body也是脚本。
如:
setb""
for{seti[expr[llength$a]-1]}{$i>=0}{incri-1}{
lappendb[lindex$a$i]
}
while的例子——假设变量a是一个链表,下面的脚本把a的值复制到b:
setb""
seti[expr[llength$a]-1]
while{$i>=0}{
lappendb[lindex$a$i]
incri-1
}
foreach命令的两种形式:
1、foreachvarNamelistbody
第一个参数varName是一个变量,第二个参数list是一个表(有序集合),第三个参数body是循环体。
每次取得链表的一个元素,都会执行循环体一次。
如:
setb""
foreachi$a{
setb[linsert$b0$i]
}
2、foreachvarlist1list1varlist2list2...body
本语句是上一个的增强形式:
可以有多个变量、列表对参与条件判断
五、Tcl过程
TCL支持过程的定