目录
引言
-
TCL(Tool Command Language)是一种
解释执行
的脚本语言,提供通用的编程能力:支持
变量、过程和控制结构
;同时还拥有功能强大的固有的
核心命令集
。 -
TCL的解释器是用一个C/C++语言的
过程库
实现的,可把TCL看作一个
C库
(有丰富的用于扩展TCL命令的C/C++过程和函数),每个应用程序都可根据需要对TCL语言进行扩展。TCL良好的可扩展性使其很好地适应产品测试的需要。 -
扩展后的TCL语言会继承TCL核心部分的所有功能,包括
核心命令、控制结构、数据类型、对过程的支持
等。
脚本学习核心
-
TCL脚本执行依赖于
解释器
(
逐行执行
); -
TCL有效命令行以
命令+字符串
(结合空格间隔符)形成; - 明白置换($、[ ]、\)和引用(” “、{ })的差别和联系;
- 理解命令eval、expr、source、exec的差别;
- 掌握{*}配合glob等返回list后的操作。
基本语法
-
一个TCL脚本可包含一个或多个命令,命令间必须用
换行符
或
分号
隔开。下面两个脚本均合法:
set a 1
set b 2
或set a 1; set b 2
-
TCL的每个命令包括一个或几个单词,第一个代表
命令名
,另外的单词则为该命令的
参数
,单词间必须用
空格
或
TAB键
隔开。
置换
-
TCL解释器在分析命令时,把所有命令参数都当作
字符串
看待,例如:
% set x 10 //定义变量x并把其值赋为10
10
% set y x+100 //y的值是x+100,而不是期望的110
x+100
-
如何告诉TCL解释器我们期望的是变量X的值呢,可以使用
置换
功能,TCL提供三种置换:
变量置换、命令置换和反斜杠置换
。
变量置换
-
变量置换
由$符号标记
,使变量的值插入一个单词中,例如:
% set y $x+100 //y的值是10+100,x被置换成其值10
- 此时y的值是10+100而不是110,TCL解释器将其视为一个字符串而不是表达式,要想得到110,还需用命令置换。
命令置换
-
命令置换是
由[ ]括起来的TCL命令及其参数
,命令置换会导致某个命令的所有或部分单词被另一个命令的结果所代替。例如:
% set y [expr $x+100]
110
-
y的值为110,当TCL解释器遇到 ‘[’ 时,会把随后的expr作为一个命令名,激活与expr对应的C/C++过程,并把’expr’和变量置换后得到的’10+100’传递给该命令过程进行处理。若去掉[ ]则会报错,因为
只把命令行的第一个单词看作命令
,其他单词均作为普通字符串处理,视为命令的参数。
反斜杠置换
-
类似于C语言中反斜杠的用法,主要用于
在单词符号中插入诸如换行符、空格、[、$等
被TCL解释器当做特殊符号对待的字符。例如:
% set msg multiple \ space //msg的值为multiple space
-
如果没有’‘则TCL回报错,因为解释器会把这里最后两个单词之间的空格认为是分隔符,于是发现set命令的参数超过两个从而报错。加入’’以后空格不被当作分隔符,’multiple space’被认为是一个单词(word)。
例如:
% set a \x48 //对应\xhh
H //十六进制的48是72,对应字符H
双引号和花括号
-
TCL提供双引号和花括号使解释器
把分隔符和置换符等特殊字符当作普通字符
,而不作特殊处理。 -
TCL解释器对双引号中的各种分隔符不作处理,但
对换行符及$和[ ]两种置换符会照常处理
。
% set y "$x ddd"
100 ddd
-
注释符
是’#‘,’#’和直到所在行结尾的所有字符都被TCL视为注释,不作任何处理。
注意:①尽量在单独一行进行注释;②不要在if/for循环内进行注释。
变量
简单变量
-
一个TCL的简单变量包含两部分:
名字和值
。两者都可以是
任意字符串
。 -
TCL解释器在分析一个变量置换时,只把
从$符号往后直到第一个不是字母、数字或下划线的字符之间的单词符号
作为要被置换的变量的名字。
% set a 2 % set a.1 4 % set b $a.1
2 4 2.1 //初衷是4
-
如果变量名中
有不是字母、下划线或数字的字符
,又要用置换,可以用
花括号
把变量名括起来。
% set b ${a.1}
4
-
TCL中的set命令能
生成一个变量
、也能
读取或改变一个变量的值
。
% set a {kdfj kjdf} % set a
kdfj kjdf kdfj kjdf
数组
-
数组是一些元素的集合。TCL的数组和普通计算机语言中的数组有很大区别。TCL
不能单独声明一个数组,数组只能和数组元素一起声明
。数组中数组元素的名字包含两部分:
数组名和数组中的元素名
,TCL中数组元素名(下标)可以为任何字符串。
% set day(monday) 1 //名为day的数组,在其中生成一个名为monday的数组元素,并把值置为1
相关命令
-
unset
——从解释器中
删除变量
,它后面可以有任意多个参数,每个参数是一个变量名,可以是
简单变量、数组或数组元素
。
% unset a b day(monday)
-
append
——把文本
加到
一个变量的后面。
% set txt hello % append txt "!How are you"
hello hello!How are you
-
incr
——把一个变量值
加上一个整数
。要求变量原值和新加的值都必须是整数。
% set b 2; incr b 3 //结果为5
表达式
- TCL支持常用的数学函数,表达式中数学函数的写法类似于C\C++语言的写法,数学函数的参数可以是任意表达式,多个参数之间用逗号隔开。
% set x 2 % expr 2*sin($x<3)
2 1.68294196962
-
expr的语法为:
expr arg ?arg ...?
两个?之间的参数表示可省(后续对可省参数都使用这种表达形式)。 -
需要注意:
数学函数并不是命令,只在表达式中出现才有意义
,即在expr之后出现才有意义。
List
-
list用于表示集合,是
由一堆元素组成的有序集合
;list可以
嵌套定义
,其每个元素可以是任意字符串,也可以是list。 -
语法:
list ? value value ...?
生成一个list
,其元素就是所有的value。
% list 1 2 {3 4} //1 2 {3 4}
-
语法:
concat list ?list...?
整合
两个list。
% concat {1 2 3}{4 5 6} //{1 2 3 4 5 6}
-
语法:
lindex list index
返回list的
第index个
元素。
% lindex {1 2 {3 4}} 2 //3 4
-
语法:
llength list
返回
list的
元素个数**。
% llength {1 2 {3 4}} //3
-
语法:
linsert list index value ?value...?
list中
插入元素
。
% linsert {1 2 5 6} 1 7 8 //1 7 8 2 5 6
-
语法:
lappend varname value ?value ...?
把每个value的值作为一个元素附加到变量varname后面。
% lappend a 1 2 3 //1 2 3
控制流:if命令
-
语法:
if test1 body1 ?else bodyn?
- TCL先把test1当作一个表达式求值,若值非0则把body1当作一个脚本执行并返回所得值;否则把test2当作一个表达式求值,若值非0则把body2当作一个脚本执行并返回所得值。
if {$x>0}{
...
}elseif{$x==1}{
...}elseif{$x==2}{
...}else{
...}
-
注意‘{’一定要写在上一行
,否则TCL解释器会认为if命令在换行符已经结束了;同时
if和{之间应该有一个空格
,否则TCL解释器会把‘if{’作为一个整体命令导致出错。
循环命令
while
-
语法:
while test body
参数test是一个表达式,body是一个脚本,如果
表达式的值非0则运行脚本直到表达式为0才停止
循环,此时while命令中断并返回一个空字符串。此处是一个脚本
set b " "
set i [expr [llength $a]-1]
while {$i>=0}{
lappend b [lindex $a $i]
incr i -1
} //变量a是一个链表,脚本把a的值复制到b
for
-
语法:
for init test reinit body
参数init是一个初始化脚本,test是用来决定循环什么时候中断的表达式,reinit是一个重新初始化的脚本,body是一个代表循环体的脚本。 - 假定变量a是一个链表,下面脚本把a的值复制到b(同上例):
set b " "
for {set i [expr [llength $a]-1]} {$i>=0} {incr i -1} {lappend b [lindex $a $i]}
foreach命令
-
语法:
foreach varname list body
参数varname是一个变量,list是一个表(有序集合),body是循环体。
每次取得链表的一个元素,都会执行循环体一次
。
set b " "
foreach i $a{
set b [linsert $b 0 $i]
} //同上两例
switch命令
-
语法:
switch ?options ? string {pattern body ?pattern body ...?}
-
options是可选参数,表示进行匹配的方式,共支持三种:
-exact方式、-glob方式、-regexp方式
;缺省情况表示-glob方式。-exact方式表示的是精确匹配,-glob方式的匹配方式和string match命令的匹配方式相同,-regexp方式是正则表达式的匹配方式。 - string是要被用来作测试的值;花括号里括起来的是一个或多个元素对。
% switch $x { //一旦switch命令找到一个模式匹配就执行相应的脚本
b {incr t1} //并返回脚本的值,作为switch命令的返回值
c {incr t2}}
命令
-
在循环体中,可以用
break
和
continue
命令中断循环。break是结束整个循环过程并从循环中跳出,continue只是结束本次循环。 -
source
命令
读一个文件并把这个文件的内容作为一个脚本进行求值
。
% source e:/tcl&c/hello.tcl
-
eval命令是一个用来
构造和执行TCL脚本
的命令,其语法为:
eval arg ?arg ...?
- 它可以接收一个或多个参数,然后把所有参数以空格隔开组合到一起成为一个脚本,然后对该脚本进行求值。
% eval set a 2;set b 4
过程
- TCL支持过程的定义和调用,过程(proc)可看作是用TCL脚本实现的命令,效果与TCL的固有命令相似。
% proc add {x y} {expr $x+$y}
- proc命令的第一个参数是要定义的过程的名字;第二个参数是过程的参数列表,参数之间用空格隔开;第三个参数是一个TCL脚本,代表过程体。proc生成一个新的命令,可以像固有命令一样调用:
% add 1 2 //3
-
在定义过程时可以
利用return命令在任何地方返回你想要的值
。return命令迅速中断过程,并把它的参数作为过程的结果。
% set a 4
4
% proc sample {x} {
global a
incr a
return [expr $a+$x]}
% sample 3
8
% set a
5
局部变量和全局变量
-
如果想在过程内部
引用一个全局变量的值
,可使用global命令。 -
全局变量a在过程中被访问。在过程中对a的改变会直接反映到全局上。如果去掉语句
global a
,则TCL会报错,因此它不认识变量a。 -
对于在过程中定义的变量,因为它们
只能在过程中被访问
,当过程退出时会被自动删除,所以称为
局部变量
;在所有过程之外定义的变量称为
全局变量
。 -
TCL中局部变量和全局变量可以同名,
两者作用域的交集为空
;
局部变量的作用域是它所在的过程内部;全局变量的作用域则不包括所有过程的内部
。这一点和C语言有很大的不同。
字符串操作
-
因为TCL把
所有输入都当作字符串
看待,所以提供来较强的字符串操作功能。 -
语法:
format formatstring ?value value...?
-
format命令类似于ANSIC中的sprintf函数,按formatstring提供的格式,
把各个value的值组合到formatstring中形成一个新字符串返回
。
% set name John //John
% set age 20 //20
% set msg [format "%s is %d years old" $name $age] //John is 20 years old
-
语法:
scan string format varName ?varName ...?
-
scan
命令可认为是
format命令的逆
,其功能类似于ANSIC中的sscanf函数。它按format提供的格式分析string字符串,然后把结果存到变量varName中,注意
除了空格和TAB键之外,string和format中的字符和’%’必须匹配
。
% scan "some 26 34" "some %d %d" a b
% set a //26
% set b //34
-
语法:
regexp ?switchs? ?--? Exp string ?matchVar? \ ?subMatchVar subMatchVar...?
-
regexp命令用于
判断正则表达式exp是否全部或部分匹配字符串string
,匹配返回1,否则返回0。
文件访问
-
TCL提供丰富的文件操作命令,通过这些命令可以
对文件名进行操作(查找匹配某一模式的文件)、以顺序或随机方式读写文件、检索系统保留的文件信息(如最后访问时间)
。 - TCL中文件名和Windows表示文件的方法有些区别:在表示文件的目录结构时它使用’/‘,而不是’’。
-
open name ? access ?
open命令
以access方式打开文件name
,返回供其他命令(get,close等)使用的
文件标识
。
文件的打开方式和C语言类似,有以下方式:
-
r 只读方式打开(默认方式),文件必须已存在。
-
r+ 读写方式打开,文件必须已存在。
-
w 只写方式打开文件,若文件存在则清空文件内容,否则创建新的空文件。
-
w+ 读写方式打开文件,若文件存在则清空文件内容,否则创建新的空文件。
-
a 只写方式打开打开文件,文件必须存在,并把指针指向文件尾。
-
a+ 读写方式打开文件,并把指针指向文件尾。若文件不存在,创建新的空文件。
====================================================================================== -
Open命令返回一个字符串用于标识打开的文件
。当调用别的命令对打开的文件进行操作时,就可以使用这个文件标识符。TCL有三个特定的文件标识:
stdin、stdout和stderr
,分别对应标准输入、标准输出和错误通道,任何时候都可以使用它们。 -
gets field ?varname?
读field标识的文件的下一行,忽略换行符
。如果命令中有varname就把该行赋给它,并返回该行的字符数(文件尾返回-1),如果没有varname参数,返回文件的下一行作为命令结果(如果到了文件尾,就返回空字符串)。 -
puts ?-nonewline? ?field? string puts
命令
把string写到field中
,如果没有nonewline开关的话,添加换行符。field默认是stdout。命令返回值为空字符串。 -
flush field
把
缓冲区内容
写到field标识的文件中,命令返回值为空字符串。 -
flush命令迫使缓冲区数据写到文件中。flush知道数据被写完才返回。当文件关闭时缓冲区数据会自动flush。
proc tgrep {pattern filename}{
set f [open $filename r]
while{[gets $f line]}{
if{[regexp $pattern $line]}{
puts stdout $line
}
}
close $f
}//TCL文件I/O的基本特点示例
-
TCL提供两个命令管理当前工作目录:
pwd和cd
。
pwd和UNIX下的pwd命令完全一样,返回当前目录的完整路径。
cd也和UNIX命令一样,使用一个参数,可以把工作目录改变为参数提供的目录。若cd没使用参数,UNIX下会把工作目录变为启动TCL脚本名的用户的工作目录。 -
TCL提供两个命令进行文件名操作:
glob和file
,用于
操作文件或获取文件信息
。 -
glob
命令采用一种或多种模式作为参数,并
返回匹配这个(些)模式的所有文件的列表
。 -
语法为:
glob ? switches ? pattern ? pattern ...?
glob命令的模式采用
string match
命令的匹配规则。例如:
% glob *.c *.h
main.c hash.c hash.h
file delete *.tmp // 不生效 不执行通配符展开
-
先使用
glob
命令返回文件列表,再使用参数展开语法{*}把列表元素作为独立参数提供给指令:
file delete {*}[glob *.tmp]
-
也可选择使用
eval
:
eval file delete [glob *.tmp]
file有许多选项的常用命令,可用来进行文件操作也可以检索文件信息:
-
file atime name
返回一个
十进制的字符串
,表示
文件name最后被访问的时间
。时间是以秒为单位从1970年1月1日12:00AM开始计算。如果文件name不存在或查询不到访问时间就返回错误。例如:
% file atime license.txt 975945600
-
file copy ?-force? ?--? source target
——这个命令把source中指明的
文件或目录递归的拷贝到目的地址targetDir
,只有当存在
-force
选项时,已经存在的文件才会被覆盖。试图覆盖一个非空的目录或以一个文件覆盖一个目录或以一个目录覆盖一个文件都会导致错误。 -
file mkdir dir ?dir ...?
——
创建
dir中指明的
目录
。 -
file owned name
——如果name被当前用户
拥有
,返回1,否则返回0。 -
file executable name
——如果name对当前用户是
可以执行的
,返回1,否则返回0。
常用命令
- cd 切换目录
- dir 显示目录中的内容
- tree 显示目录结构
- md 创建目录
- rd 删除目录
- copy 拷贝文件
- move 移动文件
- del 删除文件 注意:目录及子目录都不会扇出
- type 显示文本文件内容
- more 逐屏的显示文本文件内容
- doskey/history 命令历史