前言

TCL(Tool Command Language)是一种解释型编程语言,它的主要设计目标是提供一个简单易用的脚本语言,而且可以方便地嵌入到其他程序中。TCL最初由约翰·奥斯汀(John Ousterhout)在1988年开发。TCL被广泛应用于自动化测试、GUI设计和网络编程等领域。

基础语法

一. 变量

变量用于存储TCL命令所使用的值。TCL中的变量使用set命令进行创建和赋值,无需提前声明。变量名区分大小写,调用变量时使用$符号。
使用set_app_var命令为变量赋值。set_app_var命令确保指定的变量实际上是一个工具特定的变量,并且还执行了数据类型检查。
例如,要设置search path,使用以下命令:
set_app_var search_path {./user/synopsys/libraries/}

要为用户定义的变量赋值,则需要使用set命令。 如果变量不存在,工具会创建它并将其初始值设置为指定的值。
例如,要创建名为my_design的用户定义变量,并将其值设置为TOP_DESIGN,使用以下命令:
set my_design TOP_DESIGN
使用unset命令删除用户定义的变量,但无法删除工具定义的特定变量。

1. 变量的数据类型

变量可以是字符串、列表、数组等多种类型。

a) 列表

列表是TCL中一种数据结构,是元素的有序集合,元素可以包含任何字符串,如空格、反斜线、换行符等,可以把列表赋值给一个变量、作为参数传给命令、嵌套到其他列表中。
通过set命令创建列表,该命令后有两个参数:列表名、列表包含的元素。元素位于一个大括号之内且以空格为界,如果某个元素中包含空格,则将该元素放在大括号或双引号之内。
TCL列表除了用[list ],还可以使用双引号或花括号等来定义。

代码如下(示例):

#创建列表x
set x "a b c";
puts "Item at index 2 of the list{$x} is : [lindex $x 2]\n";
#创建列表y
set y {a b {cd} {e f {g h}}}
puts "Treated as a list : $y\n"
#创建列表z
set z [list puts "arg 2 is $y"];
puts "A command resemble : $z\n";

#执行结果
a b c
Item at index 2 of the list{a b c} is : c

a b {cd} {e f {g h}}
Treated as a list : a b {cd} {e f {g h}}

puts {arg 2 is 12 3 56}
A command resemble : puts {arg 2 is 12 3 56}
b) 数组

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

代码如下(示例):

set day(monday) 1; set day(tuesday) 2 #第一个命令生成一个名为day的数组,同时在数组中生成一个名为monday的数组元素,并把值置为1,第二个命令生成一个名为tuesday的数组元素,并把值置为2
set a monday; set day(monday) 1; set b \$day(monday); set c $day(\$a)  #b的值为1,即day(monday)的值,c的值为1,即day(monday)的值

c) 字符串

TCL中的字符串可以使用单引号或双引号括起来,还支持使用花括号来表示字符串。

代码如下(示例):

set text "Hello World"
set text ‘Hello World’
set text {Hello World}
#执行结果
Hello World
Hello World
Hello World

2. 变量置换、引用和匹配

a) 置换

TCL中包括三种变量替换方式:变量替换$,命令替换[]和反斜杠替换\。

i) 变量替换$

在这里插入图片描述
变量替换由$触发,如果变量名不是由字母数字和下划线组成的,那么在$时,要将变量名加上花括号。
在这里插入图片描述

ii) 命令替换[]

在这里插入图片描述
[]是返回命令执行的结果,多用于赋值和条件判断。

iii) 反斜杠替换\

在这里插入图片描述
\是转义字符,将一些特殊字符当成字面量输出。

b) 引用

在TCL中的引用表示的是可以阻止解释器对一些特殊字符(即在tcl中视为命令的字符)将其按照字符串输出其字面量,也就是直接输出他自己,不让其执行命令功能。

i) 反斜杠\

第一,他可以进行转义,将一些特殊功能的字符,当成字符输出
第二,当我们写命令时,一行写不下的话,可以在后面加上 \,之后换行写后续的命令,这表示下一行的命令跟上一行是同一行命令(需要注意的是\后面不能有空格)
第三,反斜杠\可以阻止调用$的转换,将调用$解析成字符串$。

ii) 双引号“”

弱引用:使用双引号引起来,里面可以进行特殊字符的使用。

iii) 大括号{}

强引用:只要是被强引用引起来的,都要被视为字符串,进行输出,特殊字符丧失功能变为普通字符。
在这里插入图片描述

c) 匹配

TCL中存在三种匹配方式:exact、glob和regexp。

i) exact

exact是严格匹配,即两边内容必须严格一致,才会匹配的上。

ii) glob

glob则是模糊匹配,可以使用一些通配符进行模糊匹配,如下图的表格,这些通配符是glob自带的,不是正则表达式,可以会有一些与正则表达式有不同的含义。
在这里插入图片描述

iii) regexp

regexp命令用于判断正规表达式exp是否全部或部分匹配字符串string,匹配返回1,否则0。
在这里插入图片描述

代码如下(示例):

set text "Hello World"
regexp {Hello} $text
#执行结果
1

二. 控制结构

TCL中的控制流和C语言类似,包括if、while、for、foreach、switch、break、continue等命令。

1. if

语法: if test1 body1 ?elseif test2 body2 elseif… ? ?else bodyn?
TCL先把test1当作一个表达式求值,如果值非0,则把body1当作一个脚本执行并返回所得值,否则把test2当作一个表达式求值,如果值非0,则把body2当作一个脚本执行并返回所得值……。需要注意的是:
1、如果逻辑表达式作为条件,则表达式前面不需要加expr
2、if 和 { 要在一行,包括elseif 和 {也要写在一行
3、各部分之前要有空格分隔
其中第二个if在}的左边少了一个] ,由此可以看到,对于条件判断,想要拿到某些命令的值,需要在外面加[],且对于条件判断来说,逻辑表达式不需要expr
但是对于计算表达式,还是加上expr为好,同时需要[]来得到计算结果,例如if {[expr $a + $b] > 3} {
在这里插入图片描述

2. while

语法: while test body
参数test是一个表达式,body是一个脚本,如果表达式的值非0,就运行脚本,直到表达式为0才停止循环,此时while命令中断并返回一个空字符串。
例如: 假设变量 a 是一个链表,下面的脚本把a 的值复制到b: set b " " set i [expr [llength $a] -1] while { $i>=0}{ lappend b [lindex $a $i] incr i -1 }

3. for

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

4. foreach

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

5. switch

和C语言中switch语句一样,TCL中的switch命令也可以由if命令实现。只是书写起来较为烦琐。 switch命令的语法为: switch ? options? string { pattern body ? pattern body …?}
switch有几个option可选,默认情况下,他是exact匹配,也就是严格完全匹配;加了-glob,就可以实现模糊匹配;加了-regexp,则表示进行正则表达式的匹配。
在这里插入图片描述

6. break

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

7. continue

在循环体中,可以用break和continue命令中断循环。其中continue只是结束本次循环。
在这里插入图片描述

三. 过程函数

过程函数是封装了一系列代码并且可以重复调用执行的代码块。在TCL中,定义函数使用“proc”关键字。其中,全局变量是在所有过程之外定义的变量。局部变量是对于在过程中定义的变量,因为它们只能在过程中被访问,并且当过程退出时会被自动删除。
在这里插入图片描述

代码如下(示例):

proc add {a b} {
return [expr $a + $b]
}
add 1 2 #调用add函数
#执行结果
3 

四. 文件读写

文件读写是处理数据必须要掌握的技能之一。在TCL中可以使用“open”、“close”、“gets”、“puts”等命令实现文件读写功能。
在这里插入图片描述

代码如下(示例):

set fileHandle [open “test.txt” r] #打开了一个名为test.txt文件
set content [gets $fileHandle] #将其内容读取到$content变量中
puts $content #通过“puts”命令输出出来
close $fileHandle #关闭文件句柄

五. 注释

TCL脚本的注释使用"#"

六. 其他常用命令

1. exec

exec 命令执行系统命令并捕获输出,不仅能执行系统命令,还能捕获它们的输出。这在自动化测试或运行外部工具时非常有用。

代码如下(示例):

# 执行 ls 命令并捕获其输出
set result [exec ls]
puts $result

2. redirect

重新指定输出的文件,例如把source文件产生的文件写到另外一个路径的文件里面。

代码如下(示例):

redirect -tee -file ./compile.log {source -echo -verbose compile.tcl}

3. eval

eval命令在Tcl中用于执行动态创建的Tcl代码。它可以接收字符串作为参数,并将其作为Tcl代码执行。
语法:eval arg ?arg …?
参数说明:arg为Tcl代码的字符串表示。可以包含变量、命令、表达式等等,这些Tcl代码会在eval命令执行时被解释执行。

代码如下(示例):

set code {puts "Hello, world!"}
eval $code
输出:
Hello, world!
#首先定义了一个变量code,它的值是一个包含Tcl代码的字符串。然后使用eval命令执行该字符串,Tcl会把字符串解释为代码并执行,最终输出Hello, world!

4. info

info 命令能够获取关于当前环境的信息,如命令名、变量名、调用栈等。

代码如下(示例):

puts [info commands]  ;# 获取所有可用命令
puts [info vars]  ;# 获取所有变量
puts [info level] ;# 获取当前调用栈深度

5. source

source 命令作用是读取一个tcl文件,并将文件内容作为tcl脚本运行。

代码如下(示例):

source dc.tcl

高级特性

一. 列表处理

TCL语言中处理列表的一些基本命令能够帮助程序员有效地管理和操作列表数据,比如concat、lappend、llength、lindex、lrange、linsert、lreplace、lsearch、lsort、join 、split和foreach等命令。
在这里插入图片描述

二. 字符串处理

因为 TCL 把所有的输入都当作字符串看待,所以 TCL 提供了较强的字符串操作功能,TCL 中与 字符串操作有关的命令有:string、format、regexp、regsub、scan 等。

1. string

语法:string option arg ?arg…?
string 命令具有强大的操作字符串的功能。
在这里插入图片描述

2. regexp

语法:regexp ?switchs? ?–? exp string ?matchVar?\ ?subMatchVar subMatchVar…?
regexp 命令用于判断正规表达式 exp 是否全部或部分匹配字符串 string,匹配返回 1,否则 0。

代码如下(示例):

set text "Hello, World!"
if {[regexp {Hello} $text]} {
    puts "文本中包含 'Hello'。"
}

3. regsub

语法:regsub ?switchs? exp string subSpec varname
regsub 的第一个参数是一个整个表达式,第二个参数是一个输入字符串,这一点和 regexp 命 令完全一样,也是当匹配时返回 1,否则返回 0。不过 regsub 用第三个参数的值来替换字符串 string 中和正规表达式匹配的部分,第四个参数被认为是一个变量,替换后的字符串存入这个 变量中。

代码如下(示例):

regsub  {there}  “they live there lives”  their  x  #正则表达式为 there ,匹配字符串中的单词 there,将其替换为 their,并将替换后的字符串存入变量 x, 返回 1,所以变量 x 的值就是  $x="they live their lives" 

注意 regsub 有个选项 -all,如果没有这个开这个选项,则只替换第一个匹配, 否则替换所有匹配到的目标。

4. format

语法:format formatstring ?vlue value…?
format 命令类似于 ANSIC 中的 sprintf 函数和 MFC 中 CString 类提供的 Format 成员函数。 它按 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

5. scan

语法:scan string format varName ?varName …?
scan 命令可以认为是 format 命令的逆,其功能类似于 ANSI C 中的 sscanf 函数。它按 format 提供的格式分析 string 字符串,然后把结果存到变量 varName 中,注意除了空格和 TAB 键之 外,string 和 format 中的字符和’%'必须匹配。例如:

代码如下(示例):

scan "some 26 34" "some %d %d" a b
输出:2
set a
输出:26
set b
输出:34
scan "12.34.56.78" "%d.%d.%d.%d" c d e f
输出:4
puts [format "the value of c is %d,d is %d,e is %d ,f is %d" $c $d $e $f]
输出:the value of c is 12,d is 34,e is 56 ,f is 78

scan 命令的返回值是匹配的变量个数。而且,如果变量 varName 不存在的话,TCL 会自动声明该变量。

三. 文件处理

文件处理是TCL的一项重要功能之一,它可以方便地读取、修改和保存文件。
在这里插入图片描述

代码如下(示例):

file mkdir /path/to/folder #创建目录

set fileHandle [open “/path/to/file” r] #读取文件
set content [read $fileHandle]
close $fileHandle

set fileHandle [open “/path/to/file” w] #写入文件
puts $fileHandle “Hello World!”
close $fileHandle

file delete “/path/to/file” #删除文件

总结

TCL是一种功能强大且易学易用的脚本语言,在各个领域都有着广泛的应用。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐