Tcl代表"toolcommandlanguage"发音为"tickle."。它实际上包含了两个部分:一个语言和一个库。
首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。它有一个简单的语法和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。
其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充(定义新的过程)的库函数。应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读取(按钮或菜单等)。但Tcl库收到命令后将它分解并执行内建的命令,经常会产生递归的调用。
应用程序使用Tcl作为它的命令语言有三个好处:1Tcl提供了标准语法,一旦用户掌握了Tcl就可以很容易的发布命令给基于Tcl的程序。2Tcl实现了很多的功能,使你的工作变得很方便。3TCl可作为程序间通信的接口。
TclInterpreters解释器
在Tcl的数据结构中的核心是Tcl_Interp.一个解释器包含了一套命令,一组变量和一些用于描述状态的东西。每一个Tcl命令是在特定的Tcl_Interp中运行的,基于Tcl的应用程序可以同时拥有几个Tcl_Interp。Tcl_Interp是一个轻量级的结构,可以快速的新建和删除。
TclDataTypes数据类型
Tcl只支持一种数据结构:字符串(string)。所有的命令,命令的所有的参数,命令的结果,所有的变量都是字符串。请牢记这一点,所有的东西都是字符串。
然而字符串的实际解释是依赖于上下文或命令的。它有三种形式:命令(command),表达式(expresion)和表(list)。下面会讨论细节。
BasicCommandSyntax基本语法
Tcl有类似于shell和lisp的语法,当然也有许多的不同。一条Tcl的命令串包含了一条或多条命令用换行符或分号来隔开,而每一条命令包含了一个域(field)的集合,域使用空白分开的,第一个域是一个命令的名字,其它的是作为参数来传给它。
例如:seta22//相当于C中的a=22a是一个变量这条命令分为三个域:1:set2:a3:22set使用于设置变量的值的命令,a、20作为参数来传给它,a使它要操作的变量名,22是要付给的a值。
Tcl的命令名可以使内建的命令也可以是用户建的新命令,在应用程序中用函数Tcl_CreateCommand来创建。所有的参数作为字符串来传递,命令自己会按其所需来解释的参数的。命令的名字必须被打全,但Tcl解释器找不到一同名的命令时会用unknown命令来代替。
在很多场合下,unknown会在库目录中搜寻,找到一个的话,会自动生成一个Tcl命令并调用它。unknown经常完成缩略的命令名的执行。但最好不要使用。
Comments注释
和shell很象,第一个字母是'#'的Tcl字符串是注释。
Groupingargumentswithdouble-quotes用双引号来集群参数用双引号来集群参数的目的在于使用有空白的参数。例如:seta"thisstringcontainswhitespace"如够一个参数一双引号来开始,该参数会一直到下一个双引号才结束。其中可以有换行符和分号。
子替换是在正式运行该调命令之前由分析器作的
Variablesubstitutionwith$用美元符进行变量替换说白了就是引用该变量。如:setahellosetb$a//b="hello"实际上传给set命令的参数//是b,"hello"setca//b="a"
Commandsubstitutionwithbrackets命令子替换(用方括号)
例如:seta[setb"hello"]实现执行setb"hello"并用其结果来替换源命令中的方括号部分,产生一条新命令seta"hello"//"hello"为setb"hello"的返回值最终的结果是b="hello"a="hello"
当命令的一个子域以方括号开始以方括号结束,表示要进行一个命令子替换。并执行该子命令,用其结果来替换原命令中的方括号部分。方括号中的部分都被视为Tcl命令。
一个复杂一点的例子:setaxyz[setb"abc"].[setc"def"]//returnxyzabcdef
Backslashsubstitution转移符替换
\bBackspace(0x8).
\fFormfeed(0xc).
\nNewline(0xa).
\rCarriage-return(0xd).
\tTab(0x9).
\vVerticaltab(0xb).
\{Leftbrace(`{').
\}Rightbrace(`}').
\[Openbracket(`[').
\]Closebracket(`]').
\$Dollarsign(`$').
\spSpace(`'):doesnotterminateargument.
\;Semicolon:doesnotterminatecommand.
\"Double-quote.
Groupingargumentswithbraces用花扩括号来集群参数
用花扩括号来集群参数与用双引号来集群参数的区别在于:用花扩括号来集群参数其中的三种上述的子替换不被执行。而且可以嵌套。
例如:seta{xyza{bcd}}//set收到俩个参数a'xyza{bcd}'
eval{seta22setb33}//eval收到一个参数'seta22\nsetb33'
Commandsummary命令综述
1.一个命令就是一个字符串(string)。
2.命令是用换行符或分号来分隔的。
3.一个命令由许多的域组成。第一个于是命令名,其它的域作为参数来传递。
4.域通常是有空白(Tab横向制表健Space空格)来分开的。
5.双引号可以使一个参数包括换行符或分号。三种子替换仍然发生。
6.花括号类似于双引号,只是不进行三种体换。
7.系统只进行一层子替换,机制替换的结果不会再去做子替换。而且子替换可以在任何一个域进行。
8.如果第一个非控字符是`#',这一行的所有东西都是注释。
Expressions表达式
对字符串的一种解释是表达式。几个命令将其参数按表达式处理,如:expr、for和if,并调用Tcl表达式处理器(Tcl_ExprLong,Tcl_ExprBoolean等)来处理它们。其中的运算符与C语言的很相似。
!逻辑非
*/%+-
<<>>左移右移只能用于整数。
<><=>===!=逻辑比较
&^|位运算和异或或
&&||逻辑'和''或'
xy:zIf-then-else与C的一样
Tcl中的逻辑真为1,逻辑假为0。
一些例子:
5/4.05/([stringlength"abcd"]+0.0)-------------------------计算字符串的长度转化为浮点数来计算
"0x03">"2""0y"<"0x12"都返回1
seta1expr$a+2
expr1+2都返回3
Lists列表
字符串的另一种解释为列表。一个列表是类似于结果的一个字符串包含了用空白分开的很多域。例如"AlSueAnneJohn"是一个有四个元素的例表,在列表中换行符被视为分隔符。
例如:bc{de{fgh}}是一个有三个元素的列表b、c和{de{fgh}}。
Tcl的命令concat,foreach,lappend,lindex,linsert,list,llength,lrange,lreplace,lsearch,和lsort可以使你对列表操作。
Regularexpressions正则表达式
Tcl提供了两个用于正则表达式的命令regexp和regsub。这里的正则表达式实际上是扩展的正则表达式,与egrep相一致。
支持^$.+\>\<()|[]
Commandresults命令结果
每一条命令有俩个结果:一个退出值和一个字符串。退出值标志着命令是否正确执行,字符串给出附加信息。有效的返回制定议在`tcl.h',如下:
TCL_OK命令正确执行,字符串给出了命令的返回值。
TCL_ERROR表示有一个错误发生,字符串给出了错误的描述。全局变量errorInfo包含了人类可读的错误描述,全局变量errorCode机器使用的错误信息。
TCL_RETURN表示return命令被调用,当前的命令(通常是一个函数)必须立刻返回,字符串包含了返回值。
TCL_BREAK表示break已经被调用,最近的循环必须立刻返回并跳出。字符串应该是空的。
TCL_CONTINUE表示continue已经被调用,最近的循环必须立刻返回不跳出。字符串应该是空的。
Tcl编程者一般需要关心退出值。当Tcl解释器发现错误发生后会立刻停止执行。
Procedures函数
Tcl允许你通过proc命令来扩充命令(定义新的命令),定义之后可以向其它的内建命令一样使用。例如:procpf{str}{puts$str}
pf"helloworld"这里有一个初学者不注意的地方,上述的定义一定要写成那样子。而不能向下面那样写:procpf{str}{puts$str}因为proc实际上也只不过是一条命令,是以换行符或分号来结束的,用集群参数来传递函数体。proc的定义如下:procnameargstclcommand
Variables:scalarsandarrays变量:标量和向量(即数组)
向量就是数组,而标量是没有下标的变量。我们用C来类比:inti;//i是标量intj[10];//j是向量
变量不需要定义,使用的时候会自动的被创建。Tcl支持两种变量:标量和向量举个例子来说明吧,seti100setj(0)10setk(1,3)20i是标量,j是向量。引用的时候:$i$j(0)$k(1,3)
Tcl简介(二):Tcl内建命令
Tcl内建命令
Built-incommands内建的命令
Tcl提供了下面描述的内建函数。...表示参数不定
appendvarNamevalueappendvarNamevaluevaluevalue...将那一大堆value附加到varName后面。如果变量不存在,会新建一个。例子:seti"aaa"appendi"bbb""ccc"//i=aaabbbccc
arraysubcommandarrayNamearraysubcommandarrayNamearg...这是一组用于向量操作的命令。第二个参数是子命令名。
假设:seta(1)1111seta(2)2222seta(three)3333以下均以它为例子(tclsh在中运行)。
arraynamesarrayName返回一个数组元素名字的列表。tclsh>arraynamesa12three
arraysizearrayName返回数组的元素个数。tclsh>arraysizea3
下面是用于遍历的命令arrrystartsearcharrayName初始化一次遍历,返回一个遍历标示(searchId)在下面的命令是中使用。
arraynextelementarrayNamesearchId返回下一个数组中的元素。如果没有返回一个空串。
arrayanymorearrayNamesearchId返回1表示还有更多的元素。0表示没有了。
arraydonesearcharrayNamesearchId结束该次遍历。
tclsh>arraystartsearchas-1-atclsh>arraynextelementas-1-a1111tclsh>arraynextelementas-1-a2222tclsh>arrayanymoreas-1-a1tclsh>arraynextelementas-1-a3333tclsh>arraydonesearchas-1-a
注意可以同时并发多个遍历。
break跳出最近的循环。
casestringinpatListbody...casestringpatListbody...casestringin{patListbody...}casestring{patListbody...}分支跳转。例如:caseabcin{ab}{puts1}default{puts2}a*{puts3}return3.
caseain{{ab}{format1}default{format2}a*{format3}}returns1.
casexyz{{ab}{format1}default{format2}a*{format3}}returns2.注意default不可以放在第一位。支持shell文件名风格的匹配符。
catchcommandcatchcommandvarName用于阻止由于错误而导致中断执行。执行command,每次都返回TCL_OK,无论是否有错误发生。如有错误发生返回1,反之返回0。如果给了varName这被置为错误信息。注意varName是已经存在的变量。
cdcddirName转换当前工作目录。如dirName未给出则转入home目录。
closefileId关闭文件描述符。
concatarg...将参数连接产生一个表。concatab{cde}{f{gh}}return`abcdef{gh}'
continue结束该次循环并继续循环。
eoffileId如fileId已结束返回1,反之返回0。
errormessageerrormessageinfoerrormessageinfocode返回一个错误,引起解释器停止运行。info用于初始化全局变量errorInfo。code被赋给errorCode。
evalarg...将所有的参数连起来作为命令语句来执行。
execarg...仿佛是在shell下执行一条命令。execls--colorexeccat/etc/passwd>/tmp/a
exitexitreturnCode中断执行。
exprarg处理表达式。seta[expr1+1]//a=2
filesubcommandname一组用于文件处理的命令。filesubcommandnamearg...
filedirnamename返回name所描述的文件名的目录部分。
fileexecutablename返回文件是否可被执行。
fileexistsname返回1表示文件存在,0表示文件不存在。
fileextensionname返回文件的扩展名。
fileisdirectoryname判断是否为目录。
fileisfilename判断是否为文件。
filelstatnamevarName以数组形式返回。执行lstat系统函数。存储在varName。
fileownedname判断文件是否属于你。
filereadablename判断文件是否可读。
filereadlinkname都出符号连接的真正的文件名。
filerootnamename返回不包括最后一个点的字符串。
filesizename返回文件的大小。
filestatnamevarName调用stat内和调用,以数组形式存在varName中。
filetailname返回最后一个斜线以后的部分。
filetypename返回文件类型file,directory,characterSpecial,blockSpecial,fifo,link,或socket。
filewritablename判断文件是否可写。
flushfileId立即处理由fileId描述的文件缓冲区。
forstarttestnextbodyfor循环。同C总的一样。
for{seti1}{$i<10}{incri}{puts$i}
foreachvarnamelistbody类似于CShell总的foreach或bash中的for..in...
formatformatStringformatformatStringarg...格式化输出,类似于C中的sprintf。seta[format"%s%d"hello100]//a="hello100"
getsfileIdgetsfileIdvarName从文件中读出一行。setf[open/etc/passwdr]gets$f
globfilename...glob-nocomplainfilename...使用CShell风格的文件名通配规则,对filename进行扩展。ls/tmpabc
tclsh>glob/tmp/*abc当加上参数-nocomplain时,如文件列表为空则发生一个错误。
globalvarname...定义全局变量。
iftesttrueBodyiftesttrueBodyfalseBodyiftestthentrueBodyiftestthentrueBodyelsefalseBody条件判断,实在没什么说的。
incrvarNameincrvarNameincrement如果没有incremnet,将varName加一,反之将varName加上increment。
seti10incri//i=11incri10//i=21
infosubcommandinfosubcommandarg...取得当前的Tcl解释器的状态信息。
infoargsprocname返回由procname指定的命令(你自己创建的)的参数列表。如:procff{abc}{putshaha}infoargsff//return"abc"
infobodyprocname返回由procname指定的命令(你自己创建的)的函数体。如:procff{abc}{putshaha}infobodyff//return"putshaha"
infocmdcount返回当前的解释器已经执行的命令的个数。
infocommandsinfocommandspattern如果不给出模式,返回所有的命令的列表,内建和自建的。模式是用CShell匹配风格写成的。
infocompletecommand检查名是否完全,有无错误。
infodefaultprocnameargvarnameprocname的参数arg,是否有缺省值。
infoexistsvarName判断是否存在该变量。
infoglobalsinfoglobalspattern返回全局变量的列表,模式同样是用CShell风格写成的。
infohostname返回主机名。
infolevelinfolevelnumber如果不给参数number则返回当前的在栈中的绝对位置,参见uplevel中的描述。如加了参数number,则返回一个列表包含了在该level上的命令名和参数。
infolibrary返回标准的Tcl脚本的可的路径。实际上是存在变量tcl_library中。
infolocalsinfolocalspattern返回locals列表。
infoprocsinfoprocspattern返回所有的过程的列表。
infoscript返回最里面的脚本(用source来执行)的文件名。
infotclversion返回Tcl的版本号。
infovarsinfovarspattern返回当前可见的变量名的列表。
下面是一些用于列表的命令,范围可以是end。
joinlistjoinlistjoinString将列表的内容连成一个字符串。
lappendvarNamevalue...将value加入列表varName中。
lindexlistindex将list视为一个列表,返回其中第index个。列表中的第一个元素下标是0。lindex"000111222"1111
linsertlistindexelement...在列表中的index前插入element。
listarg...将所有的参数发在一起产生一个列表。listfriday[execls][execcat/etc/passwd]
llengthlist返回列表中元素的个数。setl[listsdfjsdfjhsdfsdkfj]llength$l//return3
lrangelistfirstlast返回列表中从frist到last之间的所有元素。setl[list000111222333444555]lrange$l3end//return333444555
lreplacelistfirstlastlreplacelistfirstlastelement...替换列表中的从first到last的元素,用element。setl[list000111222333444555]lreplace$l12dklfjsdfsdfdsfjhjdsf000dklfjsdfsdfdsfjhjdsf333444555
lsearch-modelistpattern在列表中搜索pattern,成功返回序号,找不到返回-1。-mode:-exact精确-globshell的通配符-regexp正则表达式
lsearch"111222333444"111//return0lsearch"111222333444"uwe//return1
lsort-modelist排列列表。-mode:-ascii-dictionary与acsii类似,只是不区分大小写-integer转化为整数再比较-real转化为浮点数再比较-commandcommand执行command来做比较
openfileNameopenfileNameaccess打开文件,返回一个文件描述符。accessrwar+w+a+定义与C中相同。如文件名的第一个字符为|表示一管道的形式来打开。setf[open|morew]setf[open/etc/passr]
procnameargsbody创建一个新的过程,可以替代任何存在的过程或命令。
procwf{filestr}{puts-nonewline$filestrflush$file}
setf[open/tmp/aw]wf$f"firstline\n"wf$f"secondline\n"在函数末尾可用return来返回值。
puts-nonewlinefileIdstring向fileId中写入string,如果不加上-nonewline则自动产生一个换行符。
pwd返回当前目录。
readfileIdreadfileIdnumBytes从fileId中读取numBytes个字节。
regexpswitchesexpstringmatchVarsubMatchVarsubMatchVar...执行正则表达式的匹配。switches-nocase不区分大小写-indices返回匹配区间如:regexp^abcabcjsdfh//return1regexp^abcabcjsdfha//return1puts$a//returnabc
regexp-indices^abcabcsdfjkhsdfa//return1puts$a//return"02"
regsubswitchsexpstringsubSpecvarName执行正则表达式的替换,用subSpec的内容替换string中匹配exp的部分。switchs-all将所有匹配的部分替换,缺省子替换第一个,返回值为替换的个数。-nocase不区分大小写。如:regsubabcabcabcbaceeeb//return1puts$b//return"eeeabcabc"
regsub-allabcabcabcabceeeb//return3puts$b//return"eeeeeeeee"
return立即从当前命令中返回。procff{}{returnfriday}
seta[ff]//a="friday"
scanstring`format'varname...从string中安format来读取值到varname。
seekfileIdoffsetorigin移动文件指针。origin:startcurrentendoffset从哪里开始算起。
setvarnamevalue设置varname用value,或返回varname的值。如果不是在一个proc命令中则生成一个全局变量。
sourcefileName从filename中读出内容传给Tcl解释起来执行。
splitstringsplitChars将string分裂成列表。缺省以空白为分隔符,也可通过splitChars来设定分隔符
stringsubcommandarg...用于字符串的命令。
stringcomparestring1string2执行字符串的比较,按Cstrcmp的方式。返回-1,0,or1。
stringfirststring1string2在string1种查找string2的定义次出现的位置。未找到返回-1。
stringlengthstring返回字符串string的长度。
stringmatchpatternstring判断string是否能匹配pattern。pattern是以shell文件名的统配格式来给出。
stringrangestringfirstlast返回字符串string中从first到last之间的内容。
stringtolowerstring将string转换为小写。
stringtoupperstring将string转换为大写。
stringtrimstring将string的左右空白去掉。
stringtrimleftstring将string的左空白去掉。
stringtrimrightstring将string的右空白去掉。
tellfileId返回fileId的文件指针位置。
tracesubcommandtracesubcommandarg...监视变量的存储。子命令定义了不少,但目前只实现了virable。tracevariablenameopscommandname为变量的名字。ops为要监视的操作。r读w写uunsetcommand条件满足时执行的命令。以三个参数来执行name1name2opsname1时变量的名字。当name1为矢量时,name2为下标,ops为执行的操作。
例如:procff{name1name2op}{puts[format"%s%s%s"name1name2op]}setahhhtracevariablear{ff}puts$a//return"ar\nhhh"
unknowncmdNameunknown并不是Tcl的一部分,当Tcl发现一条不认识的命令时会看看是否存在unknown命令,如果有,则调用它,没有则出错。
如:#!/usr/bin/tclshprocunknown{cwdargs}{puts$cwdputs$args}//下面是一条错误命令sdfdfsdfsdkhfsdjkfhkasdfjksdhfk//return"sdfdfsdfsdkhfsdjkfhkasdfjksdhfk"
unsetname...删除一个或多个变量(标量或矢量)。
uplevelcommand...将起参数连接起来(象是在concat中)。最后在由level所指定的上下文中来执行。如果level是一个整数,给出了在栈中的距离(是跳到其它的命令环境中来执行)。缺省为1(即上一层)。如:#!/usr/bin/tclprocff{}{seta"ff"//设置了局部的a-------------------------}seta"global"ffputs$a//return"global"
再看下一个:#!/usr/bin/tclprocff{}{uplevelseta"ff"//改变上一级栈中的a-------------------------------------}setaglobalffputs$a//return"ff"如果level是以#开头后接一个整数,则level指出了在栈中的绝对位置。如#0表示了顶层(top-level)。abc分别为三个命令,下面是它们之间的调用关系,top-level->a->b->c->uplevellevel绝对位置:0123当level为1或#2都是在b的环境中来执行。3或#0都是在top-level的环境中来执行。
upvarlevelotherVarmyVarotherVarmyVar...在不同的栈中为变量建立连接。这里的level与uplevel中的level是同样风格的。例如:#!/usr/bin/tclprocff{name}{upvar$namexsetx"ff"}seta"global"ffaputs$a//return"ff"
whiletestbody举个例子吧:setx0while{$x<10}{puts"xis$x"incrx}
Built-invariables内建的变量下名的全局变量是由Tcllibrary自动来管理的。一般是只读的。
env环境变量数组。如:puts$env(PATH)//return/bin:/usr/bin:/usr/X11R6/bin
errorCode当错误发生时保存了一些错误信息。用下列格式来存储:CHILDKILLEDpidsigNamemsg当由于一个信号而被终止时的信息。CHILDSTATUSpidcode当一个子程序以非0值退出时的格式。CHILDSUSPpidsigNamemsg当一个子程序由于一个信号而被终止时的格式。NONE错误没有附加信息。UNIXerrNamemsg当一个内核调用发生错误时使用的格式。
errorInfo包含了一行或多行的信息,描述了错误发生处的程序和信息。
原文的作者也是Tcl的缔造者JohnOusterhout
Tcl简介(三):Tcl内建命令
Tcl名字空间
namespace创建和操纵命令和变量的上下文(content)。
简介:一个名字空间是一个命令和变量的集合,通过名字空间的封装来保证他们不会影响其它名字空间的变量和命令。Tcl总是维护了一个全局名字空间globalnamespace包含了所有的全局变量和命令。
namespaceeval允许你创建一个新的namespace。例如:namespaceevalCounter{namespaceexportBumpvariablenum0
//添加了一个过程namespaceevalCounter{proctest{args}{return$args}}
//删除testnamespaceevalCounter{renametest""}引用:setCounter::num//return0也可以用下面的方式添加:procFoo::Test{args}{return$args}或在名字空间中移动:renameFoo::TestBar::Test