当前位置:   article > 正文

十二、TCL脚本

十二、TCL脚本


本文结合《路科验证》B站视频课进行一些TCL入门用法总结

引言

• TCL( Tool Command Language) 是一种解释执行的脚本语言( Scripting Language) ,它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。
• 由于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
  • 1
  • 2
  • 3

TCL每一命令包含一个或几个单词,第一个单词代表命令名,另外的单词则是这个命令的参数,单词之间必须用空格或TAB键隔开

置换(substitution)

TCL解释器在分析命令时,把所有的命令参数都当作字符串看待,数据类型:tcl不支持其他语言中的形如int, double ,char等等类型,唯一支持的就是string类型。

set x 10 ;        #定义变量x,并把x的值赋为10
10
set y x+100 ;	   #y的值是x+100,而不是我们期望的110
x+100
  • 1
  • 2
  • 3
  • 4

上例的第二个命令中,x被看作字符串x+100的一部分,如果我们想使用x的值’10’,就必须告诉TCL解释器:我们在这里期望的是变量x的值,而非字符’X’,怎么告诉TCL解释器呢,这就要用到TCL语言中提供的置换功能。
TCL提供三种形式的置换:变量置换、命令置换和反斜杠置换.

变量置换

变量置换由一个$符号标记,变量置换会导致变量的值插入一个单词中

set y $x+100; #y的值是10+100,这里x被置换成它的值10
10 + 100
  • 1
  • 2

这时,y的值还不是我们想要的值110,而是10+100,因为TCL解释器把10+100看成是一个字符串而不是表达式,y要想得到值110,还必须用命令置换,使得TCL会把10+100看成一个表达式并求值。

命令置换

命令置换是由[ ]括起来的TCL命令及其参数,命令置换会导致某一个命令的所有或部分单词被另一个命令的结果所代替

set y [expr $x+100];
110
  • 1
  • 2

y的值是110 , 这里当TCL解释器遇到字符’[‘时,它就会把随后的expr作为一个命令名,从而激活与expr对应的C/C++过程,并把’expr’和变量置换后得到的’10+110’ 传递给该命令过程进行处理。
• 如果在上例中我们去掉 [ ],那么TCL会报错 。因为在正常情况下 ,TCL解释器只把命令行中的第一个单词作为看作命令,其他的单词都作为普通字符串处理,看作是命令的参数。

反斜杠置换

TCL语言中的反斜杠\置换似于C语言中反斜杠的用法,主要用于在单词符号中插入诸如换行符、空格、[、$等被TCL解释器当作特殊符号对待的字符。

set msg multiplex\ space;         #msg的值为multiple space。
multiple space
  • 1
  • 2

如果没有’‘的话,TCL会报错,因为解释器会把这里最后两个单词之间的空格认为是分隔符,于是发现set命令有多于两个参数,从而报错。加入了’\‘后,空格不被当作分隔符,'multiple space‘被认为是一个单词(word)。

双引号和花括号

除了使用反斜杠外,TCL提供另外两种方法来使得解释器把分隔符和置换符等特殊字符当作普通字符,而不作特殊处理,这就要使用双引号" "和花括号({})。
TCL解释器对双引号中的各种分隔符将不作处理,但是对换行符及$和[ ]两种置换符会照常处理。

set y "$x ddd";
100 ddd
  • 1
  • 2

变量

简单变量

一个TCL简单变量包含两个部分 :名字和值。名字和值都可以是任意字符串。
TCL解释器在分析一个变量置换时,只把从$符号往后直到第一个不是字母、数字或下划践的字符之间的单词符号作为要被置换的变量的名字。

set a 2 ;    #a=2	
set a.1 4;   #a.1=4		
set b $a.1;  #b=2.1
  • 1
  • 2
  • 3

在最后—命令行,我们希望把变量a.1的值付给b,但是TCL解释器在分析时只把$符号之后直到第一个不是字母、数字或下划线的字符(这里是之间的单词符号(这里是’a’)当作要被置换的变量的名字,所以TCL解释器把a置换成2,然后把字符串付给变量b。这显然与我们的初衷不同。
如果变量名中有不是字母、数字或下划线的字符,又要用置换,可以用花括号把变量名括起来

set b ${a.1}4
  • 1
  • 2

TCL中的set命令能生成一个变量、也能读取或改变一个变量的值

set a {kdfj kjdf} ;   	  # 变量a的值是kdfj kjdf   
set a;                    #读取变量a的值
  • 1
  • 2

数组

数组是一些元素的集合。TCL数组和普通计算机语言中的数组有很大的区别。在TCL中,不能单独声明一个数组,数组只能和数组元素一起声明。数组中,数组元素的名字包含两部分:数组名和数组中元素的名字,TCL中数组元素的名字(下标)可以为任何字符串。

set day(monday) 1;
set day(tuesday) 2;
  • 1
  • 2

第一个命令生成一个名为 day 的数组 , 同时在数组中生成 一个名为monday的数组元素,并把值置为1,第二个命令生成一个名为tuesday的数组元素,并把值置为2。

其它相关命令

unset

unset这个命令从解释器中删除变量,它后面可以有任意多个参数,每个参数是一个变量名,可以是简单变量,也可以数组或数组元素。

unset a b day(monday)
  • 1
append

append命令把文本加到一个变量的后面

incr

incr命令把一个变量值加上一个整数。incr要求变量原来的值和新加的值都必须是整数

set a 10   #a=10 
incr a 10  #a=20
incr a     #a=21 没有参数默认加1
  • 1
  • 2
  • 3
表达式

TCL支持常用的数学函数,表达式中数学函数的写法类似于C\C++语言的写法,数学函数的参数可以是任意表达式,多个参数之间用逗号隔开。

set x 2;    #变量x的值是2
expr 2* sin($x<3); #表达式的值为1.68294196962
  • 1
  • 2

其中expr是TCL的一个命令,语法为:expr arg ?arg …?
­ 两个?之间的参数表示可省,后面介绍命令时对于可省参数都使用这种表示形式。

需要注意的一点是,数学函数并不是命令,只在表达式中出现才有意义,即出现在expr之后才有意义。

list

list这个概念在TCL中是用来表示集合的。TCL中list是由一堆元素组成的有序集合,list可以嵌套定义,list每个元素可以是任意字符串,也可以是list。
{} #空 list
{abed} {a {b c} d} #list可以嵌套

•语法:list  value value...
•这个命令生成list,就是所有的value。
 list 1 2 {3 4} ;                           # list的元素是1 2 {3 4}
 
•语法:concat list list...             #整合两个list
concat {1 2 3} {4 5 6}                #整合后的list为{1 2 3 4 5 6)
 
•语法:lindex list index             #返回list的第index个元素
 lindex {1 2 {3 4}} 2                    #返回list的第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...
把每个vaIue的值作为一个元素附加到变量vamame后面
 lappend a 1 2 3      #1 2 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

控制流

if

语法:if test1 body1 else bodyn
TCL先把test1当作一个表达式求值,如果值非0。则把body1当作一个脚本执行并返回所得值,否则把test2当作一个表达式求值,如果值非0,则把body2当作一个脚本执行并返回所得值。

if { $x>0 }{         #注意'{'一定要写在上一行,因为不这样,TCL解释器会认为if命令在换行符已经结束了;
	...                 #同时if'{'之间应该有空格否则TCL解释器会把if'{'作为一个整体命令导致出错
}elseif {$x==1} {
	... 
} elseif { $ x = = 2 } {  
	...
}else{
	. ..
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

for

语法:for init test reinit body
参数init是一个初始化脚本,第二个参数test是一个表达式 ,用来决定循环什么时候中断,第三个参数reinit是重新初始化的脚本,第四个参数body也是脚本,代表循环体;

set b " "
for {set i [expr [llength $a] -1]} {$i>=0} {incr i -1) {
lappend b [lindex $a $i] }
#作用和上面的例子是相同的。
 
#例如:
for {set i 0} {$i< 10} {incr i} {puts $i;}  #将打印出09
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

foreach

语法:foreach varName list body
第一个参数varName是一个变量,第二个参数list是一个表(有序集合),第三个参数body是循环体。每次取得链表的元素都会执行循环体一次。

set b " "
foreach i $a{
set b [linsert$b 0 $i]
}
  • 1
  • 2
  • 3
  • 4

变量a是一个链表,脚本把a的值复制到b。

switch

语法:switch options string { pattern body pattern
body … }
第一个是可选参数options,表示进行匹配的方式。TCL持三种匹配方式:-exact方式,-glob方式,-regexp方式,缺省情况表示-glob方式。-exact方式表示的是精确匹配,-glob方式的匹配方式和string match命令的匹配方式相同,-regexp方式是正规表达式的匹配方式。第二个参数string是要被用来作测试的值,第三个参数是括起来的一个或多个元素对。

switch $x {                  	  #一旦switch命令找到一个模式匹配
	b {incr t1}                   #就执行相应的脚本,并返回脚本的值,作为switch命令的返回值
	c {incr t2}                            
} 
  • 1
  • 2
  • 3
  • 4

命令

break/continue

在循环体中,可以用break和continue命令中断循环。其中break命令结束整个循环过程并从循环中跳出,continue只是结束本次循环。

source

• source命令读一文件并把这个文件的内容作为一个脚本进行求值

source e:/tcl&c/hello.tcl
  • 1
eval

eval命令是一个用来构造和执行TCL脚本的命令,其语法为:
eval arg arg … #它可以接收一个或多个参数,然后把所有的参数以空格隔开组合到一起 成为一个脚本,然后对这个脚本进行求值。

eval set a 2; set b 4
  • 1

过程

TCL支持过程的定义和调用,在TCL中,过程可以看做是用TCL脚本实现的命令,效果与TCL固有命令相似。

proc 命令

由proc 命令来对过程定义,相当于函数一样的作用

 proc add {x y} {expr $x+$y}
 add 1 2 	# 调用add过程,传递两个参数
# 结果为3
  • 1
  • 2
  • 3

局部变量和全局变量

用global在proc中声明变量来自外部,引用外部变量。

 set a 4 
 proc sample {x} {
	global a  #用global声明,这个变量来自外部,即全局变量
	incr a
	return [expr $a+$x]
}
 sample 3 	# 值为8
 set a  	# 值为5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

字符串操作

因为TCL把所有的输入都当作字符串看待,所以TCL提供了较强的字符串操作功能

formant

语法:format formatstring value value …

按照formatstring提供的格式,把各个value的值组合到formatstring中形成新字符串返回

%set name john
%set age 20
%set msg [format "%s is %d years old" $name $age]
//john is 20 years old
  • 1
  • 2
  • 3
  • 4

scan

语法:scan string format varName varName …

可以认为是format命令的逆命令。其功能类似于ANSIC中的sscanf函数。它按照format提供的格式分析string字符串,然后把结果存到变量varName中。

注意:除了空格和TAB键之外,string和format中的字符和百分号 % 必须匹配。

% scan "some 26 34" "some %d %d" a b
%set a	#26
%set b  #34
  • 1
  • 2
  • 3

regexp

regexp命令用于判断正则表达式exp是否全部或部分匹配字符串,匹配返回1 ,否则返回0

字符意义
.匹配人一个单个字符
^表示从头进行匹配
$表示从末尾进行匹配
[chars]匹配字符集合chars中给出的任意字符
*对*前面的项进行0次或者多次匹配
+对+前面的项进行1次或者多次匹配

文件访问

open

  • 语法: open name access

access方式打开name文件,返回字符串,用于标识打开的文件。
当调用别的命令(如:gets,puts,close)对文件进行操作时,都可以使用这个文件标识。
stdin.stdout,stderr,分别对应标准输入、标准输出和错误通道

gets

  • 语法:gets field varname

读field标识的文件下一行,忽略换行符。
如果命令有varName就把该行赋给它,并返回该行的字符数
如果没有varname,返回文件的下一行作为命令结果
如果到了文件的结尾,就返回空字符串

puts命令

  • 语法:puts nonewline field string

puts命令把string写到field中
如果没有 nonewline开关的话,就添加换行符

flush field

把缓冲区的内容写到field标识的文件中,命令返回值为空。

管理目录的指令包括:

pwd 返回当前目录的完整路径
cd 使用一个参数,把工作目录改变为参数提供的目录
glob 和 file 用来操作文件或者获取文件信息

pwd

pwd跟UNIX下的pwd命令完全一样,没有参数,返回当前目录的完整路径。

cd

cd命令也和UNIX命令一样,使用一个参数,可以把工作目录改变为参数提供的目录。如果cd 没有使用参数,UNIX下会把工作目录改为启动TCL脚本的用户的工作目录。

glob

TCL提供了两个命令进行文件名的操作:glob和file,用来操作文件或获取文件信息。
glob命令采用一种或多种模式作为参数,并返回匹配这个(些)模式的所有文件的列表

  • 语法:glob switches pattern pattern…

glob命令的模式采用string match命令的匹配规则

# 找到所有以.v和.sv结尾的文件
%glob *.v *.sv  

  • 1
  • 2
  • 3

file

  • 语法:file switches pattern pattern…
file delete *.sv   #不生效,因为file不识别*通配符
#采用一下的方式
file delete {*}[glob *.sv]
#方法二
eval file delete [glob *.sv]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

{*} 的存在,是把列表元素作为独立参数提供给指令。比如你glob *.sv返回的是多个文件,文件与文件字符串之间会有空格,tcl会把glob *.sv返回的所有文件名当做一个文件,这样file delete也就无法找到对应的文件。

file是有许多选项的常用命令,可以用来进行文件操作也可以检索文件信息。

atime

file atime filename 返回一个十进制的字符串,表示文件filename最后被访问的时间,时间是以秒为单位从1970年1月1日12:00AM开始计算。如果文件filename不存在或者查询不到访问时间就返回错误。

file atime data.txt
  • 1
copy
  • file copy ?-force? ? --? source target

这个命令把source中中指明的文件或目录递归的拷贝到目的地址target,只有当存在-force选项时,已经存在的文件才会被覆盖。试图覆盖一个非空的目录或以一个文件覆盖一个目录或以一个目录覆盖一个文件都会导致错误。

file mkdir dir ? dir ...? //创建dir中指明的目录
file owned name 		  //如果name被当前用户拥有,返回1,否则返回0
file executable name	  //如果name对当前用户是可以执行的,就返回1,否则返回0
  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/187994
推荐阅读
相关标签
  

闽ICP备14008679号