陈颂光
全栈工程师,能够独立开发从解释器到网站和桌面/移动端应用的各类软件。
关注我的 GitHub

Tcl概览

Tcl的设计理念与shell类语言很接近,都是基于文本的动态语言,甚至比bash之类语法更简单。除了字符串和文件处理方面的shell传统强项外,Tcl的事件机制又方便了打造图形用户界面和网络应用。Tcl适合用于快速原型开发、测试、包装界面和粘合,还有嵌入式系统的应用。

Tcl虽然比较低调,但还是有不少应用,以下网页罗列了一些: http://wiki.tcl.tk/37389

运行Tcl程序##

在主流GNU/Linux发行版中,很可能已经预装好Tcl/Tk。如果没有也可用常规方式轻易地安装。

REPL

和许多动态语言一样,可以方便地交互式使用Tcl,用命令tclsh即可启动。

默认命令提示符为“% ”。通过把输出提示符的Tcl脚本放到变量 tcl_prompt1 和 tcl_prompt2 可改变每个命令首行和余下行的提示符。

用文件结束符(通常通过按ctrl-D)可离开。

运行文件

如果命令存至一文件中,可以用以下命令运行它们并提供参数:

tclsh [encoding name] fileName arg  ...

字符“\032” (“\u001a”, control-Z),会导致提早退出,需用该字符请转义。

脚本

脚本(假设tclsh路径为/usr/bin/tclsh)应以

#!/usr/bin/tclsh

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" ${1+"$@"}

开始,且文件应设为可执行。后一方式好处在于不用写死tclsh的路径。

语法总结##

一个 Tcl 脚本是一个包含一个或多个命令的字符串。除了象后面描述的那样被引用之外,分号和换行是命令分隔符。除了被引用之外,右方括号在命令替换期间是命令终结符。

命令的求值分两步。 首先,Tcl 解释器把命令分解成字并按下面描述的那样完成替换。对所有命令都以同样的方式进行替换。第一个字用于定位完成这个命令的一个命令过程,接着命令的所有的字被传递给命令过程。命令过程以它喜欢的任何方式自由的解释命令的字,如一个整数、变量名、列表、或Tcl 脚本。不同的命令以不同的方式解释它们的字。

一个命令的字由空白(不包括作为命令分隔符的换行)来分隔。

如果一个字的第一个字符是双引号则字终结于下一个双引号字符。如果是分号,右方括号,或空格字符(包括换行)出现在引号之间则被作为普通的字符对待并包含在字里。象下面描述的那样,在引号之间的字符上进行命令替换、变量替换、和反斜杠替换。双引号不会作为字的一部分而保留。

如果一个字的第一个字符是左花括号,则字终结于相匹配的右花括号。花括号在字中嵌套:对于每个额外的左花括号都必须有一个对应的右花括号(但是,如果在一个字中的左括号或右括号被用一个反斜杠引用起来则在匹配右花括号时不计在内)。除了下面描述的反斜杠-换行替换之外,在花括号之间的字符上不进行替换,对分号、换行、右方括号、或白空格不做特殊的解释。字由外侧的花括号之间的字符精确地组成,不包括花括号自身。

如果一个字包含一个左方括号,则 Tcl 进行命令替换。为此将递归调用 Tcl 解释器来把左方括号后面的字符作为一个 Tcl 脚本处理。脚本可以包含任意数目的命令并且必须用一个右方括号来终结。脚本的结果(即最后的一条命令的结果)将被替换到字中方括号和它们中间所有字符的位置上。在一个单一的字中可以有任意数目的命令替换。在由花括号包起来的字上不进行命令替换。

如果一个字包含一个美元符,则 Tcl 进行变量替换:字中的美元符号和跟随的字符被一个变量的值所替换。接受下面几种形式的变量替换:

形式 意义
$name Name 是一个标量变量的名字;名字终结于任何不是字母、数字、或下划线的字符。
$name(index) Name 给出一个数组变量的名字,index 给出在这个数组中的一个元素的名字. Name 只能包含字母、数字、和下划线。index的字符将被进行命令替换、变量替换、和反斜杠替换。
${name} Name 是一个标量( scalar)变量的名字。它可以包含除了右括号之外的任何字符。

一个单一的字中可以有任意数目的变量替换。在由花括号包起来的字上不进行命令替换。

如果在一个字中出现一个反斜杠则发生反斜杠替换。除了下面描述的这些情况之外,反斜杠被删除,跟随的字符被作为普通字符对待。这就允许在字中包含象双引号、右方括号、和美元符号等字符而不触发特殊的处理。下表列出的要特殊处理的反斜杠序列 ,跟着的是每个序列被替换成的值。

转义序列 意义
\a 声音警告 (振铃) (0x7)
\b 退格 (0x8)
\f 换页 (0xc)
\n 换行 (0xa)
\r 回车 (0xd)
\t 跳格(Tab) (0x9)
\v 纵向跳格 (0xb)
\<换行>空白 一个单一的空格字符替换反斜杠、换行和在换行后面的所有空格和跳格。这个反斜杠序列是唯一一个在命令被实际分析之前在一次独立的预处理中被替换的。这意味着即使在花括号之间这个替换也发生,并且不在花括号和引号之间时作为结果的空格被作为一个字分隔符对待。
\| 反斜杠  
\ooo 数字ooo(它们中的一个、两个、或三个)给出一个八进制数,是要插入的 Unicode 字符的八进制值。 Unicode 字符的高位将是 0.
\xhh 十六进制数 hh 给出要插入的 Unicode 字符的十六进制值。可以提供任意数目的十六进制数字;但除了最后两位之外都被忽略(结果总是一个一字节的数量)。Unicode 字符的高位将是 0.
\uhhhh 十六进制数 hhhh (它们中的一个、两个、三个、或四个)给出要插入的 Unicode 字符的十六进制值。

除了前面描述的反斜杠-换行,在由花括号包起来的字上不进行反斜杠替换。

如果一个升音符 ‘#’出现在 Tcl希望是一个命令的第一个字的地方,则升音符和其后面跟随的、一直到下一个换行的所有字符,被作为一个注释对待并被忽略。注释字符只有出现在一个命令开始时才有意义。

每个字符作为建立的一个命令的某个字的一部分,被 Tcl解释器精确的处理一次。例如,如果发生了变量替换则在变量的值上不进行进一步的替换;值被原封不动的插入字中。如果发生了命令替换则嵌套的命令被对 Tcl 解释器的递归调用整个的处理;在做递归调用之前不进行替换并且对嵌套的脚本的结果不进行额外的替换。

替换不影响一个命令的字边界。例如,即使变量的值包含空格,在变量替换期间变量的整个的值成为一个单一的字的一部分。

常用命令

表达式

expr命令用于求值表达式:

expr arg ?arg arg ...?

所有参数被串接后作为表达式求值并返回结果。Tcl表达式由运算数、运算符、圆括号、逗号和空白组成。

运算数
  • 整数,可以是十进制、二进制(带前缀0b)、八进制(带前缀0o或0)、十六进制(带前缀0x)
  • 浮点数,除了通常格式还有字符串InfNaN
  • 布尔值
  • 变量名(前缀$)
  • 双引号包围的字符串,进行变量、命令和转义代换
  • 花括号包围的字符串
  • 方括号包围的命令,它将被求值
  • 数学函数(abs、acos、asin、atan、atan2、bool、ceil、cos、cosh、double、entier、exp、floor、fmod、hypot 、int、isqrt、log、log10、max、min、pow、rand、round、sin、sinh、sqrt、srand、tan、tanh、wide)

运算符

大多为左结合,优先级由高到低为:

运算符 意义
- + ~ ! 负号、正号、按位取反、逻辑否
** 幂(右结合)
* / % 乘、除、取模
+ - 加、减
« » 左移位、右移位
< > <= >= 比较(数值优先)
== != 相等、不相等
eq ne 作为字符串比较
in ni 在列表中、不在列表中
& 按位与
^ 按位异或
| 按位或
&& 逻辑与(短路)
|| 逻辑或(短路)
?: 条件(短路)

除了条件运算符,其它也可以作命令用,只用加前缀::tcl::mathop::

变量

Tcl中变量在首次赋值时创建,不用声明,也没有类型(可存任何值)。

命令 用途
set varName 返回名为varName的变量的值。
set varName value 把名为varName的变量的值设为value,返回value。
unset ?-nocomplain? ?--? ?name name name ...? 删除变量。删除一个数组元素不影响其它。
incr varName ?increment? 把名为varName的变量自增increment(默认为1),变量不存在时创建之并设为increment。返回新值
append varName ?value value ...? 把所有value接起来回到名为varName的变量的值后,变量不存在时创建之并设为所有value接起来。返回新值

其中,若varName有左圆括号且终于右圆括号,则表示数组元素,首个左圆括号前为数组名,被括的则为下标。

控制结构

过程

proc命令用于创建过程:

proc name args body

参数name为命令名,参数args为命令的形参列表,参数body为过程体(一个Tcl脚本)。过程体中的return命令则结束过程并返回return的参数。

然后可以用刚过程名作命令调用过程,调用时过程体会被运行(可用形参名访问命令的对应参数)。

apply命令可用于调用匿名过程,其语义相当于:

proc apply {fun args} {
    set len [llength $fun]
    if {($len < 2) || ($len > 3)} {
         error "can't interpret \"$fun\" as anonymous function"
    }
    lassign $fun argList body ns
    set name ::$ns::[getGloballyUniqueName]
    set body0 {
         rename [lindex [info level 0] 0] {}
    }
    proc $name $argList ${body0}$body
    set code [catch {uplevel 1 $name $args} res opt]
    return -options $opt $res
}

也就是说,apply命令的首个参数给出匿名过程(由参数列表、体和可选的名字空间组成的列表),其余参数则是传给匿名过程的参数。

分支

if命令的语法和语义与其它语言类似,其中then和else都是可选的:

if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?

首个求值为真的expr对应的body被求值并返回之,没有则求值bodyN(如有,不然返回空字符串)并返回之。

注意,在Tcl中,数0和字符串falseno表示假,其它数和字符串trueyes表示真。

switch命令则简化了基于模式匹配的多路分支:

switch ?options? string pattern body ?pattern body ...?
switch ?options? string {pattern body ?pattern body ...?}

首个匹配string的pattern对应的body被求值并返回之,最后一个pattern若为default则总匹配,没有匹配则返回空字符串。

其中options可以有:

选项 意义
-exact 精确匹配(默认)
-glob glob匹配
-regexp 正则表达式匹配
-nocase 忽略大小写
-matchvar varName 正则表达式捕获的组作为列表写到变量varName
-indexvar varName 正则表达式捕获区间作为列表写到变量varName
后面不再有选项

循环

while命令的语法和语义与其它语言类似:

while test body

每次迭代前求值test(正常应当是用花括号包围的表达式),若真则求值body,否则退出循环。退出循环时返回空字符串。

for命令的语法和语义与C/C++/Java语言类似:

for start test next body

首先求值start,每次迭代前求值test(正常应当是用花括号包围的表达式),若非零则求值body再求值next,否则退出循环。退出循环时返回空字符串。

foreach命令可以遍历一个列表:

foreach varname list body

依次对list的每个元素求值body,body中可用变量名varname访问元素。

foreach命令还可以遍历多个列表:

foreach varlist1 list1 ?varlist2 list2 ...? body

每次迭代中,依次对各varlist中变量赋以对应list的未被遍历的元素,求值body,直到所有list没有未被遍历的元素。

另外,在循环体中continue命令会通过抛出异常来中止当前最内层迭代,在循环体中break命令会通过抛出异常来中止当前最内层循环。

异常

throw命令用于抛出异常:

throw type message

其中type为方便机读的列表(应从一般到特殊),message为方便人读的错误信息。

error命令也行:

error message ?info? ?code?

catch命令用于求值Tcl脚本并捕捉异常:

catch script ?resultVarName? ?optionsVarName?
  • 若有异常在求值script时被抛出,则有关信息保存到变量resultVarName(如有),返回选项字典保存到变量optionsVarName(如有,含-code、-level,TCL_ERROR还有 -errorinfo、-errorcode、-errorline、-errorstack),返回非零的整数异常代码(1、2、3、4分别表示TCL_ERROR、TCL_RETURN、TCL_BREAK、TCL_CONTINUE)。
  • 否则,结果保存到变量resultVarName。

try命令用于求值Tcl脚本并捕捉和处理异常:

try body ?handler...? ?finally script?

首先求值body,按情况调用首个合适的handler指定的脚本,最后运行script。其中handler形如on code variableList script(匹配异常代码code)或trap pattern variableList script(匹配-errorcode以pattern为前缀的TCL_ERROR),variableList的首变量(如有)赋为求值结果或供人读的错误信息,次变量(如有)赋为选项字典。

数据结构

Tcl中的各种数据都可表示为字符串。

字符串处理

命令 用途
string bytelength string 返回string的UTF8字节长度
string compare ?-nocase? ?-length int? string1 string2 比较前int(不指定则全部)个字符,string1小于、等于、大于string2分别返回-1、0、1
string equal ?-nocase? ?-length int? string1 string2 比较string1与string2前int(不指定则全部)个字符是否相等
string first needleString haystackString ?startIndex? 返回字符串needleString在haystackString自startIndex(默认0)起首次出现位置,不出现则返回-1。
string index string charIndex 返回string的第charIndex个字符
string is class ?-strict? ?-failindex varname? string 返回string是否在类class中。其中class可为alnum、alpha、ascii、boolean、control、digit、double、entier、false、graph、integer、list、lower、print、punct、space、true、upper、wideinteger、wordchar、xdigit。-strict导致空字符串返回0。-failindex导致首个破坏这性质的指标存到变量varName。
string last needleString haystackString ?lastIndex? 返回字符串needleString在haystackString自lastIndex(默认为长度)起最后出现位置,不出现则返回-1。
string length string 返回string的字符数。
string map ?-nocase? mapping string 把string中子字符串顺序替换为mapping(格式如数组的字符串表示)中对应字符串。
string match ?-nocase? pattern string 返回string是否匹配pattern。其中模式中?匹配单个字符、*匹配零个或多个字符、\x匹配x、[chars]匹配字符集中任一字符。
string range string first last 返回string从first到last(含)的子字符串。
string repeat string count 返回由重复string共count次得的字符串。
string replace string first last ?newstring? 返回由string中把first到last(含)的子字符串换成newstring(默认空)得的字符串。
string reverse string 返回string的反转
string tolower string ?first? ?last? 返回由string中把first到last(含)的子字符串换成其小写得的字符串。
string totitle string ?first? ?last? 返回由string中把first到last(含)的子字符串换成其首字母大写得的字符串。
string toupper string ?first? ?last? 返回由string中把first到last(含)的子字符串换成其大写得的字符串。
string trim string ?chars? 返回截去string开首和结尾出现于chars(默认为各空白)中字符所得字符串
string trimleft string ?chars? 返回截去string开首出现于chars(默认为各空白)中字符所得字符串
string trimright string ?chars? 返回截去string结尾出现于chars(默认为各空白)中字符所得字符串
string wordend string charIndex 返回string中指标charIndex字符所属单词的末字符
string wordstart string charIndex 返回string中指标charIndex字符所属单词的首字符
regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...? 返回string是否部分匹配正则表达式exp。其中可用选项有-about、-expanded、-indices、-line、-linestop、-lineanchor、-nocase、-all、-inline、-start index、–。变量matchVar保存匹配部分,各subMatchVar保存捕获组。
regsub ?switches? exp string subSpec ?varName? 返回string把匹配正则表达式exp的子字符串换成subSpec所得字符串(有varName则存到它而返回匹配数)。其中可用选项有-about、-expanded、-indices、-line、-linestop、-lineanchor、-nocase、-all、-start index、–。subSpec中可用\1到\9引用捕获组,用\0引用匹配部分,用\\、\&、\n转义。
format formatString ?arg arg ...? 用sprintf风格把各arg格式化为字符串,其中格式化描述formatString中对每个arg,用%、可选标记(-、+、 、0、#之一)、可选域长度、可选精度(前缀.)、可选大小(ll、h、l之一)、类型(d、u、i、o、x、X、b、c、s、f、e、E、g、G、%)描述。
scan string format ?varName varName ...? 用sscanf风格从字符串string解析数据,依次存到各变量varName,返回成功解析个数,不指定varName则返回数据列表。其中格式化描述format中对每个域,用%、可选大小(ll、h、l、L之一)、类型(d、o、x、b、u、i、c、s、f、e、g、n、[chars]、[^chars])描述。

其中字符串中指标形如N、end-N、end+N、M+N、M-N之一,M、N均为整数,end表示末字符。

列表处理

列表的字符串表示为由空格分隔的若干字,各字依次为各元素的字符串表示。

命令 用途
list ?arg arg ...? 构造列表,其元素依次为各参数。
concat ?arg arg ...? 把所有参数分别去首尾空白后串接起来并以空格分隔,可用于串接列表。
join list ?joinString? 把列表串接成字符串。其中分隔符joinString默认为一个空格。
split string ?splitChars? 把字符串拆成列表。其中splitChars中每个字符均被视为分隔符(空则把每个字符都拆成单独元素),默认为一个空格。
llength list llength命令用于计算列表中元素个数。
lindex list ?index ...? lindex命令用于从(嵌套)列表list中取得元素,依次以各index为下标从子列表选元素。
lassign list ?varName ...? 把list各元素依次赋给各varName变量,过多的变量赋为空字符串,过多的元素列表被返回
linsert list index ?element element ...? 返回把一些元素element加入到列表list形成的新列表。
lappend varName ?value value ...? 把元素加到varName变量指向的列表后面。
lmap varname list body 返回list各元素经body映射所得列表,body中可通过变量varname访问原元素
lmap varlist1 list1 ?varlist2 list2 ...? body 返回list各元素经body映射所得列表,body中可通过varlist中变量访问原元素
lrange list first last 返回list的从第first到第last个(含)元素的子列表
lrepeat count ?element ...? 返回重复各element组成列表count次所得列表
lreplace list first last ?element element ...? 返回把list从第first到last的元素换成element所得列表
lreverse list 返回反转list元素次序所得列表
lset varName ?index ...? newValue 把varName指向嵌套列表的指定下标元素设为newValue
lsearch ?options? list pattern 返回列表首个符合指定模式的下标(除-all、-inline),没有则-1。其中可用选项有匹配方法-exact、-glob、-regexp,修饰-all、-inline、-not、-start index,内容类型-ascii、-dictionary、-integer、-nocase、-real,排序情况-sorted、-decreasing、-increasing、-bisect,子列表选项-index indexList、-subindices
lsort ?options? list 对list排序。其中可用选项有-ascii、-dictionary、-integer、real、-command command、-increasing、-decreasing、-indices、-index indexList、-stride strideLength、-nocase、-unique

数组处理

数组(散列表)的字符串表示为由空格分隔的若干字,各字依次为各条目的键和值。

命令 用途
array anymore arrayName searchId 返回是否有未迭代键
array donesearch arrayName searchId 结束迭代
array exists arrayName 返回是否有指定名称的数组
array get arrayName ?pattern? 返回有指定模式的所有条目组成的列表
array names arrayName ?mode? ?pattern? 返回有指定模式的所有键组成的列表
array nextelement arrayName searchId 返回下一个键
array set arrayName list 设置数组的部分条目
array size arrayName 返回条目数
array startsearch arrayName 开始遍历,返回searchId
array statistics arrayName 返回条目数、桶数及分布
array unset arrayName ?pattern? 删除所有有指定模式的条目或整个数组

字典处理

字典(树)的字符串表示为由空格分隔的若干字,各字依次为各条目的键和值。

命令 用途
dict append dictionaryVariable key ?string ...? 把各string依次加到字典中key对应的值(无则视为原为空字符串)
dict create ?key value ...? 创建由指定条目构成的一个字典。
dict exists dictionaryValue key ?key ...? 返回嵌套字典是否存在指定的键路径
dict filter dictionaryValue key ?globPattern ...? 返回键符合指定模式的条目组成的子字典
dict filter dictionaryValue value ?globPattern ...? 返回值符合指定模式的条目组成的子字典
dict filter dictionaryValue script {keyVar valueVar} script 返回值使script返回真的条目组成的子字典
dict for {keyVar valueVar} dictionaryValue body 对字典中每个条目求值body,body中可用keyVar、valueVar访问键、值
dict get dictionaryValue ?key ...? 返回嵌套字典中对应于指定键路径的值
dict incr dictionaryVariable key ?increment? 把increment(默认1)加到字典中key对应的值(无则视为原为0)
dict info dictionaryValue 返回统计信息
dict keys dictionaryValue ?globPattern? 返回符合特定模式(默认为所有)的所有键的列表
dict lappend dictionaryVariable key ?value ...? 把各value依次加到字典中key对应的值(无则视为原为空列表)
dict map {keyVar valueVar} dictionaryValue body 返回对各条目求值body的结果换掉值所得字典
dict merge ?dictionaryValue ...? 返回合并多个字典得到的字典,有冲突则以后者为准
dict remove dictionaryValue ?key ...? 返回删除嵌套字典中的一个条目后得到的字典
dict replace dictionaryValue ?key value ...? 返回换掉或新增嵌套字典中的一些条目后得到的字典
dict set dictionaryVariable key ?key ...? value 换掉嵌套字典中的一个条目
dict size dictionaryValue 返回字典的条目数
dict unset dictionaryVariable key ?key ...? 删除嵌套字典中的一个条目
dict update dictionaryVariable key varName ?key varName ...? body 求值body,其中可通过varName读写key对应的值
dict values dictionaryValue ?globPattern? 返回符合特定模式(默认为所有)的所有值的列表
dict with dictionaryVariable ?key ...? body 求值body,其中可通过key读写key对应的值

二进制数据处理

命令 用途
encoding convertfrom ?encoding? data 把data(每个字符低八位视为一字节)解码为字符串
encoding convertto ?encoding? string 返回string的编码
encoding dirs ?directoryList? 获得或设置编码数据文件路径列表
encoding names 返回可用编码列表
encoding system ?encoding? 获得或设置默认编码
binary decode format ?-option value ...? data 解码data,其中format可为base64(选项有-maxlen length、-wrapchar character)、hex、uuencode(选项有-maxlen length、-wrapchar character)。
binary encode format ?-option value ...? data 编码data,其中format可为base64、hex、uuencode,选项有-strict(禁空格)。
binary format formatString ?arg arg ...? 构造二进制字符串,其中格式化字符串formatString中每个域由类型描述符、可选的标记、可选的重复次数(非负十进制整数或*)描述。
binary scan string formatString ?varName varName ...? 从二进制的string提取数据,其中格式化字符串formatString中每个域由类型描述符、可选的标记(u表示无符号)、可选的重复次数(非负十进制整数或*)描述。
类型描述符 意义
a 字节字符串,不足用\0填充
A 字节字符串,不足用空格填充
b 二进制字符串,低到高
B 二进制字符串,高到低
h 十六进制字符串,低到高
H 十六进制字符串,高到低
c 八位整数
s 十六位小尾整数
S 十六位大尾整数
t 十六位整数
i 三十二位小尾整数
I 三十二位大尾整数
n 三十二位整数
w 64位小尾整数
W 64位大尾整数
m 64位整数
f 单精度浮点数
r 小尾单精度浮点数
R 大尾单精度浮点数
d 双精度浮点数
q 小尾双精度浮点数
Q 大尾双精度浮点数
x 0
X 位置回移重复次数
@ 位置移到重复次数

系统管理

文件管理

命令 用途
cd ?dirName? 改变当前目录到dirName(默认为主目录)
pwd 返回当前目录
glob ?switches? ?pattern ...? 返回有某个pattern模式的文件名列表,其中模式中?匹配单个字符、*匹配零个或多个字符、\x匹配x、[chars]匹配字符集中任一字符、{a,b,…}匹配模式之一。可用选项有-directory directory、-join、-nocomplain、-path pathPrefix、-tails、-types typeList、–
file atime name ?time? 读写文件最后访问时间
file attributes name 返回文件属性列表
file attributes name ?option? 返回文件属性
file attributes name ?option value option value...? 设置文件属性
file channels ?pattern? 返回被打开的通道列表
file copy ?-force? ?--? source target 复制
file copy ?-force? ?--? source ?source ...? targetDir 复制
file delete ?-force? ?--? ?pathname ... ? 删除
file dirname name 返回所有目录
file executable name 返回文件是否可执行
file exists name 返回文件是否存在
file extension name 返回后缀
file isdirectory name 返回文件是否目录
file isfile name 返回文件是否正常文件
file join name ?name ...? 用分量构造路径
file link ?-linktype? linkName ?target? 创建或读取链接。linktype为-symbolic、-hard之一
file lstat name varName 类似stat但不解析符号链接
file mkdir ?dir ...? 创建目录
file mtime name ?time? 读写文件最后修改时间
file nativename name 返回文件的平台相关名字
file normalize name 返回路径独一无二的表示
file owned name 返回文件是否由当前用户拥有
file pathtype name absolute、relative或volumerelative
file readable name 返回文件是否可读
file readlink name 返回符号链接的指向
file rename ?-force? ?--? source target 重命名
file rename ?-force? ?--? source ?source ...? targetDir 移动
file rootname name 返回去后缀的路径
file separator ?name? 返回路径分隔符
file size name 返回文件大小(字节)
file split name 返回路径的分量列表
file stat name varName 把文件信息数组存到变量varName,含atime、ctime、dev、gid、ino、mode、mtime、nlink、size、type、uid。
file system name 返回文件系统和可选信息的列表
file tail name 返回路径的最后分量
file tempfile ?nameVar? ?template? 创建临时文件,名字存到变量nameVar
file type name 返回文件类型(file、directory、characterSpecial、blockSpecial、fifo、link、socket之一)
file volumes 返回根列表
file writable name 返回文件是否可写

I/O

|命令|用途| |:—|:—| |open fileName ?access ?permissions??|创建一个基于文件fileName的通道。其中access形如b?[rwa]+?,其中b、r、w、a、+分别表示非文本、读、写、追加、不存在时新建空文件,默认为r。又或为元素取自RDONLY、WRONLY、RDWR、APPEND、BINARY、CREAT、EXCL、NOCTTY、NONBLOCK、TRUNC的列表。permissions为整数掩码形式的权限,默认为0666。| |socket ?options? host port|创建一个基于网络连接客户端套接字的通道。其中可用选项有-myaddr addr、-myport port、-async。| |socket -server command ?options? port|创建一个基于网络连接服务器端套接字的通道,对每个连接以参数新通道、客户端主机、客户端主机端口号调用command。其中可用选项有-myaddr addr。| |chan blocked channelId|返回上一个输入操作是否被阻塞| |chan close channelId ?direction?|关闭通道。其中direction为read或write| |chan configure channelId ?optionName? ?value? ?optionName value?...|读取或设置通道属性| |chan copy inputChan outputChan ?-size size? ?-command callback?|把inputChan至多size字节变换到outputChan。-command导致后台执行。| |chan create mode cmdPrefix|创建一个以cmdPrefix列表为处理器的通道。其中mode为read或write组成的列表。| |chan eof channelId|返回通道是否已到末尾。| |chan event channelId event ?script?|设置或取得事件处理器。其中event为readable或writable| |chan flush channelId|清洗输出缓冲区| |chan gets channelId ?varName?|读一行到变量varName| |chan names ?pattern?|返回通道列表| |chan pending mode channelId|返回已缓存的字节数| |chan pipe|返回一个管道的读、写通道列表| |chan pop channelId|取消最上层转换| |chan postevent channelId eventSpec|提示eventSpec列表(由read或write组成)中事件发生。| |chan push channelId cmdPrefix|加入上层转换| |chan puts ?-nonewline? ?channelId? string|把string写入通道。-nonewline则在后面加换行。| |chan read channelId ?numChars?|读至多numChars个字符| |chan read ?-nonewline? channelId|读字符串| |chan seek channelId offset ?origin?|设置当前位置。其中origin为start、current或end。| |chan tell channelId|当前位置的已读字节数,不支持则返回-1| |chan truncate channelId ?length?|设置最大字节数|

optionName 意义 可选值
-blocking boolean 是否阻塞 0、1
-buffering newValue 缓存量 full、line、none
-buffersize newSize 缓存字节大小  
-encoding name 编码  
-eofchar char 结束字符  
-eofchar {inChar outChar} 结束字符  
-translation mode 换行 auto、binary、cr、crlf、lf
-translation {inMode outMode} 换行 auto、binary、cr、crlf、lf

进程管理

命令 用途
exec ?switches? arg ?arg ...? ?&? 分别作为子进程调用各arg。其中可用选项有-ignorestderr、-keepnewline、–。&导致马上返回子进程pid列表,否则返回最后一个命令写到标准输出的内容。
pid 返回当前进程的pid。
pid fileId 返回open命令返回fileID对应的子进程pid列表。
coroutine name command ?arg...? 创建名为name的协程,它运行时以arg为参数调用command,command返回后协程不复存在。返回yield或return的参数
yield ?value? 挂起当前协程,让value(默认空)作为当前协程生成的值。
yieldto command ?arg...? 挂起当前协程,转而运行用参数arg调用command。返回值为协程下次被调用时的参数。
vwait varName 进入事件循环,直至变量varName被修改后才返回。
update ?idletasks? 进入事件循环,直至事件队列被清空才返回(有idletasks参数则只清此前的事件)。
exec的特殊参数 用途
| 上一命令的标准输出重定向到下一命令的标准输入
|& 上一命令的标准输出和错误重定向到下一命令的标准输入
< fileName 首个命令的标准输入重定向到名为fileName的文件
<@ fileId 首个命令的标准输入重定向到通道fileId
« value 首个命令的标准输入重定向为值value
> fileName 最后一个命令的标准输出重定向到名为fileName的文件
2> fileName 所有命令的标准错误重定向到名为fileName的文件
>& fileName 最后一个命令的标准输出和所有命令的错误重定向到名为fileName的文件
» fileName 最后一个命令的标准输出附加到名为fileName的文件
2» fileName 所有命令的标准错误附加到名为fileName的文件
»& fileName 最后一个命令的标准输出和所有命令的错误附加到名为fileName的文件
>@ fileId 最后一个命令的标准输出重定向到通道fileId
2>@ fileId 所有命令的标准错误重定向到通道fileId
2>@1 所有命令的标准错误重定向到标准输出
>&@ fileId 最后一个命令的标准输出和所有命令的错误重定向到通道fileId

日期时间

命令 用途
time script ?count? 返回调用script共count(默认1)次的平均流逝时间。
after ms 睡眠ms毫秒
after ms ?script script script ...? 马上返回一个id并在ms毫秒后求值concat起来的script。
after cancel id 不再要求完成id
after cancel script script ... 不再要求完成concat起来的script
after idle script ?script script ...? 马上返回一个id并在事件循环有空时求值concat起来的script。
after info 返回事件处理器id列表
after info id 返回脚本、idle/timer组成的列表
clock add timeVal ?count unit...? ?-option value? 返回timeVal加上指定偏移量,其中count为整数,unit为seconds、minutes、hours、days、weeks、months、years之一。
clock clicks 返回尽可能准确的时间,单位和起点不详。
clock format timeVal ?-option value...? 格式化以秒为单位的时间值timeVal。
clock microseconds 返回当前时间,以微秒为单位,由1970年开始。
clock milliseconds 返回当前时间,以毫秒为单位,由1970年开始。
clock scan inputString ?-option value...? 解析时间字符串为以秒为单位的时间值。
`clock seconds 返回当前时间,以秒为单位,由1970年开始。
选项 意义
-base time 指定时间基点,。
-format format 指定格式化格式,其中可用的格式化标记见下表。
-gmt boolean 是否用UTC时间,false表示用本地时间。
-locale localeName 设置决定格式的本地化区域。
-timezone zoneName 指定时区,默认取自环境变量TCL_TZ或TZ。
格式化标记 意义
%a 周天的缩写
%A 周天
%b 月份的缩写
%B 月份
%c 日期时间的本地表示
%C 世纪
%d
%D 相当于%m/%d/%Y
%e 所在月的总日数
%Ec 本地历法日期时间的本地表示
%EC 本地历法纪元的表示
%EE 公元前后的本地表示
%Ex 本地历法日期的表示
%EX 时间的本地表示
%Ey 本地历法年数
%EY 本地历法年的表示
%g 对应%V的两位年
%G 对应%V的四位年
%h 相当于%b
%H 小时(00-23),24小时制
%I 小时(12-11),12小时制
%j 年中的日(001-366)
%J 犹太日数
%k 小时(0-23),24小时制
%l 小时(12-11),12小时制
%m 月(01-12)
%M 分钟(00-59)
%N 月(1-12)
%Od, %Oe, %OH, %OI, %Ok, %Ol, %Om, %OM, %OS, %Ou, %Ow, %Oy 与没有O相比本地表示
%p 上下午,小写优先
%P 上下午,大写优先
%Q 内部使用
%r 时间的本地表示,12小时制
%R 时间的本地表示,24小时制
%s 作为整数
%S 秒(00-59)
%t 制表符
%T 相当于%H:%M:%S
%u 周天(1-7)
%U 年中的周数(00-53),首个周日在第1周
%V 年中的周数(01-53),首个周四在第1周
%w 周天(0-6)
%W 年中的周数(00-53),首个周一开始第1周
%x 日期的本地表示
%X 时间的本地表示
%y 两位年
%Y 四位年
%z 时区如+hhmm或-hhmm
%Z 时区名的本地表示
%% 字符%
%+ 相当于%a %b %e %H:%M:%S %Z %Y

杂项

命令 用途
eval arg ?arg ...? 将所有参数串接起来交给Tcl解释器求值并返回结果
source ?-encoding encodingName? fileName 求值存于文件中的Tcl脚本并返回结果
rename oldName newName 把原名为oldName的命令改名为newName
tailcall command ?arg ...? 尾调用
exit ?returnCode? 结束当前进程,返回returnCode(默认0)给系统。
history add command ?exec? 在历史列表中增加命令,exec表示现在求值它。
history change newValue ?event? 修改历史事件event(默认-1)为newValue。
history clear 清除历史记录
history event ?event? 返回历史事件event(默认-1)
history info ?count? 返回给人读的历史记录字符串
history keep ?count? 设置和读取历史记录数上限(默认20)
history nextid 返回下一个历史事件应有的编号
history redo ?event? 重新求值历史事件event(默认-1)

其中event可为整数(正数指定事件编号、非正指定以当前为0的相对编号,如-1表示上一命令)或字符串(表示最近以之开首或按string match匹配的命令)。

本文未涉及命令

  • 作用域。 global、uplevel、upvar、namespace、variable
  • 包。 package、pkg::create、pkg_mkIndex
  • I/O。fileevent、http、zlib
  • 面向对象。oo::class、oo::copy、oo::define、oo::objdefine、oo::object、my、self、next、nextto
  • 平台相关。platform、platform::shell、registry、dde
  • 调试工具。memory、tcltest、trace、info
  • 杂项Tcl工具。auto_execok、auto_import、auto_load、auto_mkindex、auto_qualify、auto_reset、tcl_findLibrary、parray、tcl_endOfWord、tcl_startOfNextWord、tcl_startOfPreviousWord、tcl_wordBreakAfter、tcl_wordBreakBefore、tcl::prefix、tm、subst、load、unload、safe、bgerror、interp、unknown

全局变量

一些变量在Tcl中有特殊意义,可以从它们得到有用信息,但没事最好不要改它们。

变量 意义
argc 参数个数(不含脚本名)
argv 参数列表
argv0 文件名(没有则为调用tclsh的名)
tcl_interactive 是否交互式(1表示是,0表示否)
auto_path 自动加载的目录列表,初始含环境变量TCLLIBPATH、全局变量tcl_library、 tcl_library的父目录、tcl_pkgPath
env 环境变量数组
errorCode 最近返回的-errorcode
errorInfo 最近返回的-errorinfo
tcl_library Tcl系统库脚本所在目录
tcl_patchLevel Tcl版本
tcl_pkgPath Tcl包脚本所在目录列表
tcl_platform 系统信息数组,键含byteOrder debug machine os osVersion pathSeparator platform pointerSize threaded user wordSize
tcl_precision 从0到17的整数,默认值0表示浮点数的字符串表示不损失精度下尽可能短,否则表示浮点数的字符串表示最多有效的十进制位数
tcl_rcFileName 启动脚本位置
tcl_traceCompile 编译期跟踪的详细程度(默认0不跟踪,1跟踪过程调用,2跟踪指令)
tcl_traceExec 运行期跟踪的详细程度(默认0不跟踪,1跟踪过程调用,2跟踪过程调用和参数,3跟踪指令)
tcl_wordchars 决定字字符的正则表达式
tcl_nonwordchars 决定非字字符的正则表达式
tcl_version Tcl版本

其它包

Tk包提供图形界面支持。Tk现在比Tcl还要常见,很多Perl、Python、Ruby程序都依赖于它。msgcat包可提供国际化支持。

thread包提供线程支持。

tdbc包提供SQL数据库接口,其实现包括tdbc::mysql、tdbc::odbc、tdbc::postgres、tdbc::sqlite3。

总结

Tcl和很多脚本语言一样,相当灵活,做一件事有多种可考虑的方式。例如Tcl/Tk内置的命令已经显示出不一致性:

  • 有时用command为回调参数,有时则用script和变量名为参数(后者导致扭曲的作用域机制)
  • 有时用面向对象的方式设子命令,有时则用更命令式的方式

作为脱水语言,动态弱类型提供了一些便捷性,也沿袭了shell类语言的脆弱性(和Scheme比很明显)。Tcl的成就主要归于其内置命令比一般的shell丰富和扩展包特别是Tk。