tcl 语言入门

1. 简介

TCL(Tool Command Language,工具命令语言)是一种功能强大且易于学习的 脚本语言,广泛应用于快速开发、测试自动化、过程控制及嵌入式系统等领域。

  • 来源:TCL 最初由 John Ousterhout 于 1980 年代末在加州大学伯克利分校开发,用于创建用户界面工具。

  • 特点:简单灵活、内置字符串处理功能强大、易于嵌入到其他应用程序中。

  • 运行 TCL 脚本:使用 tclsh 命令来执行 TCL 脚本文件,例如 tclsh script.tcl。

1.1 语言特点

  • 一个 TCL 脚本可以包含一个或多个命令。

  • 命令之间必须用换行符或分号隔开。

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

  • 使用 # 进行注释

TCL 解释器对一个命令的求值过程分为两部分:分析和执行。

  • 在分析阶段,TCL 解释器运用规 则把命令分成一个个独立的单词,同时进行必要的置换(substitution);
  • 在执行阶段,TCL 解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应 的 C/C++ 过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。

1.2 tcl 语言命令速查

类别 命令 说明 示例
变量操作 set 设置变量值 set name "Alice"; puts $name
unset 删除变量 set name "Alice"; unset name
array 数组操作命令 array set myArray {a 1 b 2}; puts $myArray(a)
info 获取变量信息 info exists name; info vars
字符串处理 string 字符串操作命令 string length "Hello"
concat 连接字符串 concat "Hello" " " "World"
split 分割字符串 split "a,b,c" ,
join 连接列表为字符串 join {a b c} ,
format 格式化字符串 format "%s is %d years old" $name $age
scan 解析字符串 scan "some 26 34" "some %d %d" a b
列表操作 list 创建列表 set mylist [list a b c]
lindex 获取列表元素 lindex $mylist 1
lappend 向列表添加元素 lappend mylist d
llength 获取列表长度 llength $mylist
lrange 获取列表子范围 lrange $mylist 0 2
lreplace 替换列表元素 lreplace $mylist 1 2 "x" "y"
lsearch 在列表中搜索 lsearch $mylist "b"
lsort 排序列表 lsort $mylist
数值计算 expr 表达式计算 expr 5 * 10
incr 增加变量值 set x 5; incr x
rand 生成随机数 rand
流程控制 if 条件判断 if {$x > 10} {puts "x is large"}
else 条件判断的”否则”分支 if {$x > 10} {puts "x is large"} else {puts "x is small"}
elseif 条件判断的”否则如果”分支 if {$x > 10} {puts "x is large"} elseif {$x < 5} {puts "x is small"}
for 固定次数的循环 for {set i 0} {$i < 10} {incr i} {puts $i}
foreach 遍历列表 foreach item {a b c} {puts $item}
while 条件循环 while {$x < 10} {incr x; puts $x}
switch 多条件选择 switch $color {red {puts "Color is red"} green {puts "Color is green"}}
break 退出循环 while 1 {if {$x > 10} break; incr x}
continue 跳过当前迭代 for {set i 0} {$i < 10} {incr i} {if {$i == 5} continue; puts $i}
字典操作 dict 字典操作命令 dict create name "John" age 30
dict get 获取字典值 dict get $mydict name
dict set 设置字典值 dict set mydict city "New York"
dict unset 删除字典键值 dict unset mydict city
dict exists 检查字典键是否存在 dict exists $mydict age
dict size 获取字典大小 dict size $mydict
dict keys 获取字典所有键 dict keys $mydict
dict values 获取字典所有值 dict values $mydict
dict lappend 向字典列表添加元素 dict lappend mydict list "a" "b"
dict for 遍历字典 dict for {k v} $mydict {puts "$k: $v"}
数组操作 array set 定义数组 array set day {monday 1 tuesday 2}
array names 获取数组所有索引 array names day
array get 获取数组索引 - 值对 array get day
array exists 检查数组是否存在 array exists day
array size 获取数组大小 array size day
parray 打印数组内容 parray day
过程与函数 proc 定义过程(函数) proc add {a b} {return [expr $a + $b]}
uplevel 在上级作用域执行命令 uplevel #0 {puts "Hello"}
upvar 访问上级作用域的变量 upvar 1 x y
eval 执行字符串作为命令 eval "puts hello"
文件 I/O open 打开文件 set fid [open "file.txt" r]
close 关闭文件 close $fid
read 读取文件内容 set data [read $fid]
gets 从文件读取一行 gets $fid line
puts 向标准输出或文件写入 puts "Hello, World!"
file 文件系统操作 file exists "file.txt"
其他实用 source 执行脚本文件 source "script.tcl"
exec 执行外部命令 exec ls -l
package 管理扩展包 package require Tk
load 加载扩展库 load ./mylib.so
catch 捕获错误 catch {error "test"} msg
error 生成错误 error "An error occurred"
网络 socket 创建网络套接字 set sock [socket localhost 8080]
fconfigure 配置套接字 fconfigure $sock -buffering line
日期时间 clock 日期时间操作 clock format [clock seconds]
time 测量命令执行时间 time {puts "Hello"} 10
其他 trace 设置变量跟踪 trace add variable x write {puts "x changed"}
rename 重命名命令 rename puts old_puts
  1. 替换机制
    • $:变量替换(如 $name
    • []:命令替换(如 [expr 5 * 10]
    • "":双引号允许替换,但会将内容视为一个整体
    • {}:花括号禁止替换,内容被视为纯字符串
  2. 数据类型:Tcl 中所有数据类型都被视为字符串,变量值始终是字符串,类型由上下文决定。
  3. 执行顺序:Tcl 的语句执行顺序是:先分组,再替换,最后执行。

2. 开始 TCL

2.1 变量声明与赋值

2.1.1 赋值与输出

TCL 中基本数据类型只有一种:字符串类型,tcl 的所有数据类型最终都可以表示为字符串。

赋值时无需声明变量类型。

变量声明语法:set 变量名 数据

数据类型分为:

  • 字符串或数字。引号可带可不带,当字符串中有空格时,才必须加引号;数字内部存储为字符串
  • 列表,用大括号(花括号)表示
  • 数组
  • 句柄
#!/bin/tclsh

set aa "hello world"            ;# 字符串
set bb    10                      ;# 字符串
set cc {red bule green}         ;# 列表
set marks(english) 92           ;# 数组
set myfile [open "filename" r]  ;# 句柄

unset cc marks myfile

puts $aa
puts $bb

使用 puts 来输出变量的值:puts $ 变量名

使用 unset 来删除变量:unset 变量名 1 变量名 2...

一个 TCL 的简单变量包含两个部分:名字和值。名字和值都可以是任意字符串。

例如一个名为“1323 7&*: hdgg”的变量在 TCL 中都是合法的。不过为了更好的使用置换 (substitution), 变量名最好按 C\C++ 语言中标识符的命名规则命名。 TCL 解释器在分析一个变量置换时,只把从$ 符号往后直到第一个不是字母、数字或下划线的字符之间的单词符号作为要被置换的变量的名字。

为了界定变量名的开始和结束,建议使用 { } 限制变量名

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

2.1.2 更改变量

  • append: 加文本
  • incr:加值
#!/bin/tclsh

set aa "hello"
append aa " world"
puts $aa ;# 输出:hello world

set x1 10
incr x1 1
puts $x1 ; 输出:11

2.1.3 命令构造

tcl 使用 eval 命令用来构造和执行 TCL 脚本,其语法为:

eval command arg1 arg2...

eval 目的是构造单一脚本,将后面的部分拼接成字符串,整体解析执行

  • eval 一般是非必要的,只要按照命令用法写参数,可以直接执行。
  • 但是如果存在变量替换,有可能被替换参数的命令会报错,这个时候就可以使用 eval 解决这个问题

举例如下:

假如一个命令用法是:create polygon layer x1 y1 x2 y2... xn yn

#!/bin/tclsh

set coord1 "0 0 100 100"
set coord2 {0 0 100 100}

create polygon tgt 0 0 100 100 ;# 可以运行

create polygon tgt $coord1 ;# 报错
create polygon tgt $coord2 ;# 报错

上述 create polygon 会执行 报错,因为 coord 是字符串或者列表,而命令要求的输入是直接的数字或字符。解决如下:

eval create polygon tgt $coord1
eval create polygon tgt $coord2

eval 会把后面的部分整体解析执行。

2.2 置换

TCL 解释器在分析命令时,把所有的命令参数都当作字符串看待

2.2.1 变量置换 variable subtitution

变量置换由一个 符号标记,变量置换会将变量代表的值进行替换。

#!/bin/tclsh

set x 10
set y $x+100
puts $y ;# 输出为:10+100

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

2.2.2 命令置换 command substitution

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

#!/bin/tclsh

set x 10
set y [expr $x+100]
puts $y ; #输出为:110

当 TCL 解释器遇到字符’[‘时,它就会把随后的 expr 作为一个命令名,从 而激活与 expr 对应的 C/C++ 过程,并把’expr’和变量置换后得到的’10+110’传递给该命令过 程进行处理。

注意,[]中必须是一个合法的 TCL 脚本,长度不限。

[]中脚本的值为最后一个命令的返回值, 例如:

#!/bin/tclsh

set y [expr $x+100;set b 300]
puts $y ; #输出为:300

有了命令置换,实际上就表示命令之间是可以嵌套的,即一个命令的结果可以作为别的命令的参数。

2.2.3 反斜杠置换(backslash substitution)

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

反斜杠置换符 \ 主要用于连接两行或者取消空格的分隔符属性,或者取消其他的特殊符号的作用

#!/bin/tclsh

set aa hello\ world; #空格为分隔符, \ 后接空格会取消空格的分割作用

set x 10
set y \$x

puts $y   ; #输出为 $x

2.3 双引号和括号

TCL 解释器对双引号" " 中的各种分隔符将不作处理,但是对换行符及 []两种置换符会照常处理。例如:

#!/bin/tclsh

set aa "hello world"
set bb "$aa nihao!"

而在花括号 { } 中,所有特殊字符都将成为普通字符,失去其特殊意义,TCL 解释器不会对其作特 殊处理。例如:

#!/bin/tclsh

set bb {$aa nihao!}

单引号 (')

  • 作用 没有特殊作用 。单引号在 Tcl 的基本语法中 不被视为引号,它只是一个普通的字符。

2.4 注释

TCL 中的注释符是’#’,’#’和直到所在行结尾的所有字符都被 TCL 看作注释,TCL 解释器对注释将不作任何处理。不过,要注意的是,’#’必须出现在 TCL 解释器期望命令的第一个字符出现的地方,才被当作注释。

#!/bin/tclsh

#This is a comment  
set a 100 # Not a comment  
wrong # args: should be "set varName ?newValue?"  

set b 101 ; # this is a comment  

要在命令行后面写注释,需要用分号分隔符

第二行中’#’就不被当作注释符,因为它出现在命令的中间,TCL 解释器把它和后面的字符当作命令的参数处理,从而导致错误。而第四行的’#’就被作为注释,因为前一个命令已经用一个分号结束,TCL 解释器期望下一个命令接着出现。现在在这个位置出现’#’,随后的字符就被当作注释了。

2.6 字符串

2.6.1 常规方法

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

  • 字符串切片string range str first last。返回 str 中从 first 到 last 指定索引范围内的所有字符。first 和 last 指定索引

  • 字符串替换string replace str first last newstring。first 和 last 指定了替换的范围。

  • 删除字符string trim str chars。去掉 chars 字符,如果没有指定 chars 字符,则去掉空白符(包括空格符、制表符、换行符、回车符)。trim 对字符串开头和结尾都操作。

  • 去掉开头或结尾 string trimleft str charsstring trimright str chars

  • 字符串比较是否相等string equal -nocase -length int str1 str2。相同返回 1,不同返回 0

    • -nocase 的意思就是不区分大小写。
    • -length int 中的 int 就是需要比较的前面几个字符。
    set res [string equal "hello world" "Hello World"]
  • 字符串查找string first -exact substring str start,返回索引

    • 如果使用了 -exact 选项,匹配会变得严格,即只有在大小写和字符顺序都完全匹配的情况下才会返回匹配位置。如果省略 -exact,则匹配是大小写不敏感的。
    • substring,需要查找的子串
    • start,一个数字,指定开始查找位置
    set res1 [string first "tcl" "This is a tcl example"]
    set res2 [string first "is" "This is a tcl example" 4]
    set res3 [string first "is" "This is a tcl example"]
  • 字符串查找string last substring str last,与 first 命令相似,只是返回的是从尾部开始搜索到的匹配的字符段

  • 返回索引到的字符string index str charIndex,字符串的索引从 0 开始

  • 重复字符串string repeat str count。返回一个把 str 重复 count 次的字符串。

  • 全小写字符串string tolower str first last。将一个字符串全部变为小写形式。first 和 last 指定了转换的范围。

  • 全大写字符串string totitle str first last

  • 首字符大写string toupper str first last

  • 格式化输出format string value1 value2...

    set msg [format "%s is %d years old" $name $age] 
  • 返回字符串类型string is class -strict -failindex varname str。如果 string 是指定 class 中的成员就返回 1,否则返回 0。如果指定了 -strict,空字符串就返回 0,不指定则返回 1。如果指定了 -failindex varnane,那么将导致不匹配的索引储存在 varname 中,如果返回 1 则 varname 不会被赋值。

    • string is lower "This" 返回 0

    • class 支持以下选项:

    class 类型

还有一些其他的就不一一列举了。

2.6.2 字符串匹配

2.6.2.1 简单匹配

语法:[string match pattern str]。如果 str 匹配 pattern 就返回 1,否则返回 0。使用的是通配风格的匹配。

  • string match 不支持正则表达式,仅支持简单通配符,例如:* ? [0-9A-Za-z]

举个例子:

  if {[string match "hello*" "hello world"]} {
      puts " 匹配成功 "
  } else {
      puts " 匹配失败 "
  }

  string match {a*[6-81A-Z]xyz\*} "abcd6xyz*"
  # 使用大括号包括整个参数,来避免出现变量置换或者分隔符等一些问题,[6-81A-Z]表示匹配 6,7,8,1,A,B,C,D,...X,Y,Z

2.6.2.2 复杂匹配

语法:[regexp pattern string match subMatch1...]

  • pattern:匹配规则
  • string:待匹配的字符串
  • match:保存匹配的正则表达式结果
  • subMatch1:Submatch1 到 Submatchn 是可选的子匹配变量,用于保存子匹配模式的结果

if {[regexp {hello\s\w+} "hello world" match]} {
    puts " 匹配成功: $match"
} else {
    puts " 匹配失败 "
}

regexp {([A-Za-z]*)} "Tcl Tutorial" a b 
puts "Full Match: a"; #Full Match: Tcl
puts "Sub Match1:b" ; #Sub Match1: Tcl

匹配符号和其他语言一般的正则表达式基本是一致的,下面给出一部分例子:

匹配规则

regexp 可用的开关列表如下:

  • -nocase 用于忽略大小写。

  • -indices 存储匹配子模式的位置,而不是匹配的字符。

  • -line 新行敏感匹配。忽略换行符后的字符。

  • start index 设置搜索模式的起始偏移量。

2.5 数组

2.5.1 简单数组

数组是一些元素的集合。TCL 的数组和普通计算机语言中的数组有很大的区别。在 TCL 中,不能单独声明一个数组,数组只能和数组元素一起声明。

数组中,数组元素的名字包含两部分:数组名 数组中元素的名字,TCL 中数组元素的名字(下标〕可以为任何字符串。例如:

#!/bin/tclsh

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

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

monday 和 tuesday 可以理解为数组的下标。

#!/bin/tclsh

set day(monday) 1  
set b $day(monday); #b 的值为 1

获取数组元素个数:array size arrayName

2.5.2 关联数组

关联数组可以看作是一种哈希表或者字典结构。

关联数组声明:array set arrName {kye1 value1 kye2 value2 ...}

举例说明:

array set person {
    name    Alice
    age     30
    city    Beijing
}
#--- 等价于:
set person(name)   Alice
set person(age)    30
set person(city)   Beijing

#--- 取值
puts $person(name)

#--- 新增
array set person {country China job Engineer}

# --- 清空
unset person
  • array names arrayName:获取所有键。
  • array exists arrayName:检查数组是否存在。
  • array get arrayName:以列表形式返回所有键值对(可用于保存状态)。
  • array size arrayName:返回元素个数。

关联数组的嵌套:

array set persons {
  name  {Alice July Mike John}
  age   {19    18    26    16}
  city  {SZ    BJ    HZ    GZ}
}

# 获取名字列表
set names $persons(name)

# 查找 "July" 的索引(从 0 开始)
set idx [lsearch -exact $names "July"]

if {$idx == -1} {
    puts "Error: July not found"
} else {
    set age  [lindex $persons(age)  $idx]
    set city [lindex $persons(city) $idx]
    puts "July's age: $age, city: $city"
}

2.7 操作数

TCL 表达式的操作数通常是整数或实数。整数一般是十进制的, 但如果整数的第一个字符是 0(zero),那么 TCL 将把这个整数看作八进制的,如果前两个字符是 0x 则这个整数被看作是十 六进制的。TCL 的实数的写法与 ANSI C 中完全一样。

以下都是合法的写法
set aa 2.1
set bb 7.9e+12
set cc  6e4
set dd  3.

TCL 支持多种运算符,比如 算术运算符,关系运算符,逻辑运算符,按位运算符,三元运算符等。参阅Tcl 运算符 | Tcl/Tk 教程

TCL 支持常用的数学函数,表达式中数学函数的写法类似于 C\C++ 语言的写法。参阅Tcl - 内置函数

这里额外介绍下条件运算符

exp?:value1:value2

#!/usr/bin/tclsh

set a 10;
set b [expr $a == 1 ? 20: 30]
puts "Value of b is $b\n"
set b [expr $a == 10 ? 20: 30]
puts "Value of b is $b\n"

2.8 列表

list 这个概念在 TCL 中是用来表示集合的。TCL 中 list 是由一堆元素组成的有序集合,list 可以嵌套定义,list 每个元素可以是任意字符串,也可以是 list。下面都是 TCL 中的合法的 list:

{} ; # 空 list  

{a b c d}  

{a {b c} d}  ;#list 可以嵌套 

2.8.1 创建列表

set listName { item1 item2 item3 .. itemn }
# or
set listName [list item1 item2 item3]
# or 
set listName [split "items separated by a character" split_character]

2.8.2 列表方法

  • 组合concat listN1 listN2...

  • 获取字符位置lindex list index

  • 获取长度llength list

  • 按位置插入元素linsert list index value1 value2...

  • 附加元素lappend varname value1 value2...

  • 替换lreplace list first last value1 value2 ...

  • 切片lrange list first last

  • 查找返回索引lsearch -exact/-glob/-regexp list pattern

    • -exact、-glob、 -regexp 是三种模式匹配的技术。
    • -exact 表示精确匹配;-glob 的匹配方式和 string match 命令的匹配方式相同;-regexp 表示正规表达式匹配
  • 分割split string splitChars ,返回 list,默认以空格分隔

  • 合并join list joinString ,合并 list 为字符串

  • 排序lsort options list

    • -ascii 按 ASCII 字符的顺序排序比较,默认方式
    • -dictionary 按字典排序,与 -ascii 不同的地方是不考虑大小写,如果元素中有数字的话, 数字被当作整数来排序
    • -integer 把 list 的元素转换成整数, 按整数排序.
    • -real 把 list 的元素转换成浮点数, 按浮点数排序.
    • -increasing 升序(按 ASCII 字符比较)
    • -decreasing 降序(按 ASCII 字符比较)
    • -command command TCL 自动利用 command 命令把每两个元素一一比较, 然后给出排序
      结果。

2.8.3 列表的嵌套

set persons {
    {name Alice age 19 city SZ}
    {name July age 18 city BJ}
    {name Mike age 26 city HZ}
    {name John age 16 city GZ}
}

2.9 控制流

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

2.9.1 if

语法为:

if { $x>0 } {  
.....  
}elseif{ $x==1 } {  
.....  
}elseif { $x==2 } {  
....  
}else{  
.....  
}  

注意,上例中’{‘一定要写在上一行,因为如果不这样,TCL 解释器会认为 if 命令在换行符处已结束,下一行会被当成新的命令,从而导致错误的结果。

2.9.2 for

语法为:

#!/bin/tclsh
for { set i 0} {$i < 10 } {incr i} {
    puts "value of a: $a"
}

2.9.3 foreach

语法为:

#!/bin/tclsh

set values {0 1 2 3 4 5}

foreach item $values {
    puts $item
}

还有另一种方式:成对取值

set x {}  
foreach {i j} {a b c d e f} {  
    lappend x $j $i  
}  
#这时总共有三次循环,x 的值为 "b a d c f e"。 

set x {}  
foreach i {a b c} j {d e f g} {  
    lappend x $i $j  
}  
#这时总共有四次循环,x 的值为 "a d b e c f {} g"。

set x {}  
foreach i {a b c} {j k} {d e f g} {  
lappend x $i $j $k  
}  
#这时总共有三次循环,x 的值为 "a d e b f g c {} {}"。

2.9.4 while

语法为:

while {$i > 0} {
...
}

在循环体中,可以用 break 和 continue 命令中断循环。

其中 break 命令结束整个循环过程, 并从循环中跳出

continue 只是结束本次循环。

2.9.5 switch

switch 命令的语法为:

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

第一个是可选参数 options,表示进行匹配的方式。TCL 支持三种匹配方式:

  • -glob 方式的匹配方式和 string match 命令的匹配方式相同,缺省情况表示 -glob 方式。

  • -exact 方式表示的是精确匹配

  • -regexp 方式是正规表达式的

第二个参数 string 是要被用来作测试的值,第三个参数是括起来的一个或多个元素对。

例子:

switch $grade  {
    A { puts "Well done!" }  
    B { puts "Excellent!" }  
    C { puts "You passed!"  } 
    F { puts "Better try again"   }   
    default {     puts "Invalid grade"   }
}

2.10 过程 procedure

TCL 支持过程的定义和调用,在 TCL 中,过程可以看作是用 TCL 脚本实现的命令,效果与 TCL 的固有命令相似。我们可以在任何时候使用 proc 命令定义自己的过程,TCL 中的过程类似于 C 中的函数。

语法为:

proc name { 形参 1 形参 2 ...} {
    ...
}

举个例子:

proc add {x y } {
    expr $x+$y
}

proc abs {x} {  
if {$x >= 0} { return $x }  
    return [expr -$x]  
}

proc add {val1 {val2 2} {val3 3}}{  
    expr $val1+$val2+$val3  
}  
#给 val2 和 val3 指定默认值

2.11 字典

2.11.1 字典定义

字典是将值映射到键的一种安排。 传统字典的语法如下所示:

dict set dictname key value

或者:

dict create dictname key1 value1 key2 value2 .. keyn valuen

举例说明:

set colours [dict create colour1 "black" colour2 "white"]
puts $colours

dict set colours  colour3 red 
dict set colours  colour4 green
puts $colours

set myDict [dict create name Alice age 30]
set myDict [dict set myDict city Beijing]  ;# 必须重新赋值!
puts [dict get $myDict name] 

dict set 不会原地修改 dict,而是返回一个 新 dict,必须用 set 重新赋值!

2.11.2 字典的使用

获取字典键值对个数:[dict size dictname]

字典中的所有键:[dict keys $dictname]

字典中是否存在键:[dict exists $dictname $key]

根据键获取值:[dict get $dictname $keyname]

字典中的所有值:[dict values $dictname]

字典的迭代:

set colours [dict create colour1 "black" colour2 "white"]
foreach item [dict keys $colours] {
   set value [dict get $colours $item]
   puts $value
}

2.12 全局变量和局部变量

对于在过程中定义的变量,因为它们只能在过程中被访问,并且当过程退出时会被自动删除,所以称为局部变量;在所有过程之外定义的变量我们称之为全局变量。TCL 中,局部变量和全局变量可以同名,两者的作用域的交集为空:局部变量的作用域是它所在的过程的内部;全局变量的作用域则不包括所有过程的内部。

如果我们想在过程内部引用一个全局变量的值,可以使用 global 命令

proc sample { x } {  
    global a  
    incr a  
    return [expr $a+$x]  
}  

全局变量 a 在过程中被访问。在过程中对 a 的改变会直接反映到全局上。如果去掉语句 global a,TCL 会出错,因为它不认识变量 a。

2.13 一些常见函数

2.13.1 系统函数

Tcl 中重要的系统函数包括,

  • clock seconds − 秒函数,返回当前时间(以秒为单位)。
  • clock format − format 函数,将秒格式化为日期和时间。
  • clock scan − scan 函数,扫描输入字符串并将其转换为秒。
  • open − 函数,用于打开文件。
  • exec − 函数,用于执行系统命令。
    • set files [exec ls "./"] 执行系统的 ls 命令
  • close − 函数,用于关闭文件。
  • glob - 函数,用于获取文件和目录,返回一个 list 结构数据
    • set rules [glob ./*.rule]
    • set rules [glob -type f *] 只返回文件
    • set rules [glob -type {f d} *] 只返回文件和目录
    • set rules [glob -directory /var/tmp/*.tmp]

下面给些示例:

#!/usr/bin/tclsh

#get seconds
set currentTime [clock seconds]
puts $currentTime

#get format 
puts "The time is: [clock format $currentTime -format %H:%M:%S]"
puts "The date is: [clock format $currentTime -format %D]"

set date "Jun 15, 2014"
puts [clock scan $date -format {%b %d, %Y}]

# 获取目录
puts [exec ls]
puts [exec dir]

## 操作文件
set filename "example.txt"
set fp [open $filename r]

# 逐行读取
while {[gets $fp line] != -1} {
    # 处理每一行(这里只是打印出来)
    puts $line
}
# 关闭文件
close $fp

2.13.2 其他常见函数

  • file 命令,用于处理文件路径,属性和操作的核心命令,支持跨平台
    • file join path1 path2...路径拼接,自动适配系统分隔符
    • file split path 将路径拆分为列表
    • file normalize path 转换路径为绝对路径
    • file dirname path提取路径的目录部分
    • file tail path 提取路径中的文件名或最后一级目录名
    • file extension path 提取路径扩展名
    • file rootname path 提取路径中的文件名,不含扩展
    • file exists path 检查目录是否存在
    • file isdirectory path 检查是否为目录
    • file isfile path 检查是否为普通文件(非目录或符号链接)
    • file size path 返回文件大小(字节)
    • file mtime path 返回文件最后修改时间
    • file copy path 返回文件类型
    • file delete path 删除文件
    • file rename path 重命名文件

2.14 面向对象编程

tcl 支持面向对象编程(OOP),主要通过扩展库实现。它类似于 C++ 对 C 的扩展,为 Tcl 提供了更结构化的编程方式,同时保持了 Tcl 的灵活性和简洁性。

类和对象 是 Tcl 面向对象编程的基础。

类是对象的模板,定义了变量和方法。对象是类的实例,拥有独立的数据和行为。

以下是一个简单的类定义示例:

package require Itcl

namespace import itcl::*

itcl::class Person {
    variable name
    variable age

    constructor {name age} {
        set this->name $name
        set this->age $age
    }

    method introduce {} {
        return "Hi, I am $name and I am $age years old."
    }
}

# 创建对象并调用方法
set person [Person new "Alice" 25]
puts [$person introduce]

Tcl 的 OOP 还支持以下特性:

  1. 继承:通过 inherit 关键字实现类的继承,子类可以复用父类的变量和方法。
  2. 多态:子类可以重写父类的方法,实现不同的行为。
  3. 封装:支持 publicprotectedprivate 修饰符,用于控制变量和方法的访问权限。

Tcl 使用命名空间(namespace)来组织代码,避免命名冲突。命名空间可以包含变量、过程和类。

这里不做更多介绍,熟悉 c/c++ 语言的朋友(正是笔者在下!)对 tcl 的类应该会举一反三,这些特性非常相似。而且一般 tcl 中我们也用不到继承多态封装的一些高级技术。


欢迎各位看官及技术大佬前来交流指导呀,可以邮件至 jqiange@yeah.net