赞
踩
Tcl 全称是Tool command Language。它是一个基于字符串的命令语言,基础结构和语法非常简单,易于学习和掌握。
Tcl 语言是一个解释性语言。所谓解释性是指不象其他高级语言需要通过编译和联结,它象其他shell 语言一样,直接对每条语句顺次解释执行。
Tcl 数据类型简单。对Tcl 来说,它要处理的数据只有一种——字符串。Tcl 将变量值以字符串的形式进行存储,不关心它的实际使用类型。
Tcl 的执行是交互式的。Tcl 提供了交互式命令界面,界面有两种:tclsh和wish。tclsh只支持Tcl 命令,wish支持Tcl 和Tk命令。通过交互界面,我们就可以象执行UNIX shell 命令一样,逐条命令执行,并即时得到执行结果。
Tcl/Tk可以提供跨平台的支持。Tcl 语言可以运行于绝大多数当今流行的UNIX、WINDOWS和Macintosh等系统上,而且命令通用,只是启动的细节有些不同。
Tcl/Tk与C/C++的良好兼容性。Tcl/Tk 脚本可以很好的集成到C/C++程序中。
#用文本编辑器创建一个文件,名为HelloWorld.tcl 并保存到目录
#输入如下一条命令后保存、关闭文件:
#puts “hello”
#!/usr/bin/tclsh
puts "hello"
在Linux环境中,最普遍的编写可执行应用程序的方法就是用“ #!” 机制。用它生成的启动脚本如下:
#!/usr/bin/tclsh
本启动脚本告诉Linux shell,用wish来运行剩余的脚本。选项-f是用来支持3.6以下的Tk版本脚本的。这种启动脚本需要提供wish或tclsh的绝对路径名。
[Angel@linux ~]$ ./HelloWorld.tcl
hello
1.输出puts
Tcl 的输出命令是“ puts” ,它会将字符串输出到标准输出channel Id。
[Angel@linux ~]$ vim HelloWorld.tcl
#!/usr/bin/tclsh
puts "Hello World!!!"
[Angel@linux ~]$ chmod 755 HelloWorld.tcl
[Angel@linux ~]$ ./HellowWorld.tcl
Hello World!!!
2.赋值 set/unset
set是变量定义和赋值命令。在定义的时候,也不必指定变量值的类型,因为变量值的类型就一种——字符串。执行set命令为变量赋值时,会在内存中为变量开辟一段内存空间。
unset命令与set命令作用相反,取消变量定义,并释放变量所占的内存空间。通过前置“ $” 符,可以引用变量的值(替换)。
set命令也可以只跟一个变量,如果此变量已经定义,会返回变量值,效果和puts类似。
[语法] set varName [value] / unset varName
例如:
[Angel@linux ~]$ vim set.tcl
#!/usr/bin/tclsh
set Clock 800MHz #变量赋值
set Data 55aa #数据Data第一次赋值
puts "Clock is $Clock, Data is $Data." #打印输出
unset Data #取消赋值
set Data 7788 #数据Data第二次赋值
puts "Data is $Data." #打印输出
[Angel@linux ~]$ ./set.tcl
Clock is 800MHz, Data is 55aa.
Data is 7788.
3.替换 $,[],{}
1) $ 符可以实现引用替换操作,用以引用参数值。Tcl 对替换只进行一遍解释,对嵌套的 “$”不于理睬。replace.tcl如下:
#!/usr/bin/tclsh
set rxdata txdata
set Data1 rxdata #变量赋值
set Data2 $$Data1 #数据Data第一次赋值
puts "rxdata is $rxdata, Data1 is $Data1, Data2 is $Data2." #打印输出
脚本执行如下:
可以看到Data2并没有二次解析$rxdata,而是直接打印输出。
[Angel@linux ~]$ ./replace.tcl
rxdata is txdata, Data1 is rxdata, Data2 is $rxdata
2).[]方括号
方括号“ []” 用来完成命令替换。用“ []” 将一条命令括起来,命令执行完成后,会返回命令执行的输出结果。
#!/usr/bin/tclsh
set b [set a 5] #将set a 5命令输出的结果赋给b
set c [expr 5*10]
puts " b is $b\n C is $c"
[Angel@linux ~]$ ./replace.tcl
b is 5
C is 50
3)." " {}
双引号和花括号将多个单词组织成一个参数。也是一种替换操作。对于" “和{}内的替换又如何处理呢?一般的原则是在” "内的替换正常进行,而在{}内的替换有可能会被阻止。
对花括号内的替换操作可以概括为:如果花括号是用做替换操作,则它会阻止内部的嵌套替换,如果花括号用做界限符,如过程定义时用做界限过程体时,不阻止替换操作,这些例子如if条件语句、循环语句、switch语句和过程声明、数学表达式等。{ }的作用比较特殊,需要根据不同的情况区别处理。
#!/usr/bin/tclsh
set b [set a 5] #将set a 5命令输出的结果赋给b
set c [expr 5*10]
puts " b is $b\n {C is $c}" # 花括号阻止替换
可以看到变量打印的C 仍为$c 并没有替换为50
[Angel@linux ~]$ ./replace.tcl
b is 5
C is $c
尽管Tcl 是基于字串操作的,但它仍旧提供了有效数学运算和逻辑运算的功能。通过命令expr可以实现对数学表达式的分析和计算。如表4.1
如表4.2 数学函数
math.tcl脚本如下:
#!/usr/bin/tclsh
set a 10
set b 5
set c [exper $a+$b]
set d [expr $a/$b]
puts "c is $c, d is $d...."
脚本执行结果:
[Angel@linux ~]$ ./math.tcl
c is 15, d is 2....
incr命令根据指定的步长来增加或减少参数的值。当步长为负时,减少参数值;当步长为正时,增加参数值。默认步长为+1。
#!/usr/bin/tclsh
set a 0
while {1} {
if { $a < 5 } {
incr a #默认变量+1
puts "A = $a" #打印输出新值
} else {
break #跳出while循环
}
}
脚本执行结果如下:
[Angel@linux ~]$ ./incr.tcl
A = 1
A = 2
A = 3
A = 4
A = 5
Tcl 将所有的变量值视作字符串,并将他们作为字符串来保存。下表列出了字符串操作的几个常用命令。
表 4-1 比较有用的字符串操作命令
本章主要讲述append、format、scan、binary、subst、string等命令。regexp、regsub在正则表达式一章讲述。
append 命令比较简单,它将一段字符串连接到另一字符串尾部从而组成新的字符串。此命令对变量直接修改。
#!/usr/bin/tclsh
set A hello
set B world
append A $B
puts "welcome to $A"
脚本执行结果如下:
[Angel@linux~]$ ./append.tcl
welcome to helloworld
format命令和C 语言中的printf和sprintf命令类似。它根据一组格式说明来格式化字符串。此命令不会改变被操作字符串的内容。
语法:format spec value1 value2
spec变元包含了格式说明关键词和附加文字。使用%来引入一个关键词,后跟0个或者多个修饰符,然后使用一个转换格式符结尾。
关键词的基本格式是“ %aaaB”:aaa是修饰符,B代表一种转换格式符。例如%f用于将对应位置的参数转化为浮点数。如果要使用”%”号,则可以使用%%来实现。否则会将%后的字符作为关键词来处理。
valueX是变元。对每个变元来讲,其关键词可多达6部分:
格式转换符:
格式标志符:
位置说明符i$表示从第i个变元取数值而不是根据通常的位置对应关系对应的变元。位置记数从1开始。
format例子:
#!/usr/bin/tclsh
set a 20
set b [format "%x" $a] #将20转换为16进制
set c [format "%#08x" $a] #将20转换为十六进制数,并添加前缀"0x"
#总宽度为8为,右对齐(默认),前导空格用0补齐
puts "The hexa value of A = $b"
puts "The hexa value of C = $c"
执行结果:
[Angel@linux ~] ./format.tcl
The hexa value of A = 14
The hexa value of C = 0x00000014
scan命令根据格式描述符来解析一个字符串并将对应值赋给后面的变量。返回成功转换的个数。
[语法] scan string format var ? var ?
scan例子:
#!/usr/bin/tclsh
set num [scan "abcABC" "%c%c"]
puts "The ASCII code is $num"
执行结果:
[Angel@linux ~] ./scan.tcl
The ASCII code is 97 98
字符串是Tcl 中的基本数据类型,所以有大量的字符串操作命令。一个比较重要的问题就是模式匹配,通过模式匹配将字符串与指定的模式(格式)相匹配来进行字符串的比较、搜索等操作。
常用的字符串操作有:
1.string compare and equal
注意命令返回值:string compare在不同的情况下返回1,相同返回0。而string equal 和string match则恰恰相反,相等或者匹配时返回1 ,不同返回0。
#!/usr/bin/tclsh set string1 abc set string2 def set string3 abc #string compare if { [string compare $string1 $string2] == 0 } { puts "string1 is same as string2" } else { puts "string1 isn't same as string2" } #string equal if { [string equal $string1 $string3] } { puts "string1 is same as string3" } else { puts "string1 isn't same as string3" }
执行结果:
[Angel@linux ~] ./string.tcl
string1 isn't same as string2
string1 is same as string3
2.string match
string match 命令沿用了各类UNIX shell 中所使用的文件名模式匹配机制。下表给出了匹配模式的三种结构。
例子:
set string1 abc set string2 def set string3 ab #string match * if { [string match a* $string1] == 1 } { puts "string is matched " } else { puts "string isn't matched" } #string match ?? #一个"?"对应一个字符,为了匹配两个字符,必须输入两个问号。 if { [string match ?? $string3] } { puts "string is matched string3" } else { puts "string1 isn't matched string3" } # string match 以a或者b开头的字符串 if { [strimg match [ab]* bell] == 1 } { puts "string is matched" } else { puts "string is not matched" }
执行结果:
[Angel@linux~]$ ./string.tcl
string is matched
string is matched string3
string is matched
3.string replace
string replace可以用新的字符串代替字符串中指定范围内的字符,如果没有指定新字符串,则指定范围内的字符都会被删除。字符个数从0开始,另外注意:替换不改变原来字符串变量的值,只是返回更改后的新字符串。
#!/usr/bin/tclsh
set var1 welcome
set var2 china
set var3 [string replace $var2 0 4 America]
set var4 [string replace $var1 0 2]
puts "$var1 $var3"
puts "$var4"
执行结果:
[Angel@linux~]$ ./string.tcl
welcom America
come
不常用的其他字符串命令此处没有详解,省略。
一个列表可以包含子列表,即列表可以嵌套。
花括号内部代表的是子列表。当用list命令创建列表的时候,如果元素是单个的词,就不用大括弧括起来,但如果某个元素是以空格分割的字符串时,就将其看作一个子列表而用花括号括起来。注意实际的处理过程并不是这样的,要复杂一些。
#!/usr/bin/tclsh set list1 [list clock1 clock2] #list1 含有三个元素 set list2 [list $list1 clock3] #list2 有两个元素,嵌套list1 用花括号括起来 set list3 [list "data1 data2" "data3"] #list3当元素是字符串时,用花括号括起来 set str "data1 data2" set list4 [list $str data3] #列表是特殊字符串,与list3结果相同 puts "List1 is $list1" puts "List2 is $list2" puts "List3 is $list3" puts "List4 is $list4" set A are set B [list {how $A you} Angel] #花括号阻止变量替换 set C [list "how $A you" Angel] puts "$B" puts "$C"
执行结果:
[Angel@linux~]$ ./list.tcl
List1 is clock1 clock2
List2 is {clock1 clock2} clock3
List3 is {data1 date2} data3
List4 is {data1 data2} data3
{how $A you} Angel
{how are you} Angel
tcl脚本示例如下:
#!/usr/bin/tclsh ##concat set var1 {1 2} set var2 [concat $var1 3] puts "***The var2 value is $var2" ##lappend set var3 [lappend var1 "3" {4} 5] puts "***The var3 value is $var3" ##llength set num [llength $var3] puts "***The number of var3 element is $num" ##lindex set var4 {55 aa bb cc} set var5 [lindex $var4 1] set var6 [lindex $var4 end] set var7 [lindex $var4 end-1] ##获得倒数第二个元素 puts "***the lindex value is $var5" puts "***the last lindex value is $var6" puts "***the last-1 lindex value is $var7" ##lrange set var8 [lrange $var4 2 end] #返回2到结尾的列表元素 puts "***lrange return value is $var8" ##linsert and lreplace set var9 [linsert $var4 1 dddd] set var10 [lreplace $var9 1 3 you are welcome] set var11 [lreplace $var9 1 3] puts "***linsert value is $var9" puts "***lreplace value is $var10" puts "***lreplace delete 1 to 3 value is $var10" ##lsort set list "A Z n 100 200 M 20 hl" set new1 [lsort -ascii $list] set new2 [lsort -dictionary $list] puts " The new1 = $new1\n The new2 = $new2"
执行结果:
[Angel@linux~]$./test.tcl
***The var2 value is 1 2 3
***The var3 value is 1 2 3 4 5
***The number of var3 element is 5
***the lindex value is aa
***the last lindex value is cc
***the last-1 lindex value is bb
***lrange return value is bb cc
***linsert value is 55 dddd aa bb cc
***lreplace value is 55 you are welcome cc
***lreplace delete 1 to 3 value is 55 cc
The new1 = 100 20 200 A M Z hl n
The new2 = 20 100 200 A hl M n Z
下面的例子是用lsearch和lreplace一起实现在list内删除所有和匹配值匹配的元素。proc是过程定义命令,定义了一个过程ldelete。
#!/usr/bin/tclsh
##lsearch
proc ldelete {list value} {
set ix [lsearch -exact $list $value]
for {} { $ix >=0 } {} {
set list [lreplace $list $ix $ix]
set ix [lsearch -exact $list $value]
}
return $list
}
set list1 [list 123 234 123 345 123 456]
set val 123
set list2 [ldelete $list1 $val]
puts "Delete result is $list2"
执行结果如下:
[Angel@linux~]$ ./lsearch.tcl
Delete result is 234 345 456
#!/usr/bin/tclsh
##join
set new [join {we are {working now}} :]
puts "The new string after join = $new"
##split
set str /tools/eda/synopsys/scl-2021.06
set s /
set list1 [split $str $s]
puts "The new list1 after split = $list1"
set str1 helloworld
set list2 [split $str1 {}]
puts "The new list2 after split = $list2"
[Angel@linux~]$ ./join.tcl
The new string after join = we:are:working now
The new list1 after split = tools eda synopsus scl-2021.06
The new list2 after split = h e l l o w o r l d
split 的默认分割符为空白符,包括空格符、制表符和换行符。如果分割符在字符串开始位置,或者有多个分割符相连,那么split命令就会产生空列表元素,并用{}表示,分割符并不被合并。
若打算将字符串的每个字符都区分开,即将每个字符都分割成列表元素,可以将分割符指定为空字符串{},这个方法对分析和处理字符串中的每个字符时比较有用。当遇到字符串内含有特殊的字符,如空格符时,split也将其作为一个字符元素处理,为了利于区别起见,用花括号将空格元素括起来。
Tcl 数组元素的索引,或称键值,可以是任意的字符串,而且其本身没有所谓多维数组的概念。数组的存取速度要比列表有优势,数组在内部使用散列表来存储,每个元素存取开销几乎相同,而列表的存取数据花非时间与其长度成正比。
array 命令在定义数组的同时可以定义其元素和元素值。需要注意元素索引(index-n)与元素值(valun-n)要成对输入,否则会出错。用命令array set arrName “”可以定义一个空数组。用普通变量值的获取方法——替换操作来获取数组元素值:
[语法]:array set arrName { index1 value1 index2 value2 …}
#!/usr/bin/tclsh
array set arr2 {1 a 2 b 3 c 4 d}
parray arr2 #输出数组全部内容
执行结果:
[Angel@linux~]$ ./array_test.tcl
arr2(1) = a
arr2(2) = b
arr2(3) = c
arr2(4) = d
可以象使用普通变量一样来使用数组变量元素。如使用info exist来检测它是否存在,使用incr来递增它的值,使用lappend列表操作来追加列表元素等。
#!/usr/bin/tclsh
set arr(1) 10
if { $arr(1) == 10 } {
incr arr(1) #输出数组全部内容
}
puts "arr(1) = $arr(1)"
[Angel@linux~]$ ./array_test.tcl
arr(1) = 11
自定义多维数组:
#!/usr/bin/tclsh
set arr(0,0) hello
set arr(0,1) world
parray arr
[Angel@linux~]$ ./array_test.tcl
arr(0,0) = hello
arr(0,1) = world
就象字符串和列表一样,数组也有一套专门的操作命令。
另外还有:
array donesearch arr index 表示结束index标识的搜索
parray arr 用于打印arr的所有元素变量名和元素值
#!/usr/bin/tclsh
array set arr [list a AAA b BBB c CCC d DDD] #定义数组并初始化
set num [array size arr] ##数组元素个数
set list1 [array get arr] ##数组元素组成列表
puts "The arr size = $num"
puts "The list of arr = $list1"
parray arr
##array names
array set a [list "School,SH" "SH" "School,NJ" "NJ" "School,HIT" "HIT"]
puts "####Array names testing!!!####"
parray a
set b [array names a "School,*"]
puts "$b"
[Angel@linux~]$ ./array_test.tcl
The arr size = 5
The list of arr = d DDD a AAA 1 11 b BBB c CCC
arr(a) = AAA
arr(b) = BBB
arr(c) = CCC
arr(d) = DDD
####Array names testing!!!####
d(School,HIT) = HIT
d(School,NJ) = NJ
d(School,SH) = SH
School,NJ School,HIT School,SH
遍历数组:
#!/usr/bin/tclsh
array set arr1 [list 1 AAA 2 BBB 3 CCC 4 DDD]
set list1 [array names arr1]
puts "$list1"
foreach id $list1 {
puts "arr1($id)= $arr1($id)"
}
[Angel@linux~]$ ./foreach.tcl
4 1 2 3
arr1(4)= DDD
arr1(1)= AAA
arr1(2)= BBB
arr1(3)= CCC
注意:array names返回的元素索引的时候,最后一个元素的索引被放置到了列表的第一个位置上。
类似C语言,Tcl也有控制命令if、if/else、if/elseif、foreach、for、while和switch命令管理控制结构。
需要注意的是Tcl中所有的控制结构都是由命令实现,而C语言中则是一条控制语句。
此外,本节还会讲到catch和error命令,用于捕获命令执行状态和处理错误报告,还有return用于从一个过程语句返回。
[语法]
if { test expr 测试表达式} {
body1
} elseif {
body2
} else {
body3
}
说明:
1.语法中用以界定过程体的花括号一定要和if命令在同一行上!因为对Tcl 来讲,换行符就是命令结束符,所以如果在if表达式后直接换行,写成:
#这种写法会报错
if { test expr }
{
...
}
就会出错。Tcl 遇到换行后就认为命令结束,但找不到执行命令体,返回错误。其他的控制命令,还有以后的过程定义命令等等都存在这个问题。
2.如果if后面还有else/elseif命令,则要留意else/elseif的位置。else/elseif要跟在if执行命令体的后面一个花括号后,不能分行,要有空格间隔花括号和else /elseif。
3.花括号括起的表达式、执行命令体或者其他内容相当于变量存在,所以前后与其他命令元素之前要有空格,否则Tcl 会返回语法错误。
4.可以使用多个elseif来创建一连串的条件命令控制结构。
5.表达式支持变量替换和命令替换
6.表达式的计算结果如果是”true”、”yes”和非零值就判断为真,如果结果
是”false”、”no”和零则判断为假。控制命令根据表达式结果来判断是否执行相应的执
行命令体。
简单例子如下:
#!/usr/bin/tclsh
set a 10
if {$a > 15} {
puts "a is a valid value smaller than 10 !!!"
} elseif {$a > 7} {
puts "a is a valid value bigger than 7 !!!"
} else {
puts "a is not a valid value!!!"
}
[Angel@linux~] ./test.tcl
iif is a valid value bigger than 7 !!!
for命令有四个变元,start是预置条件或者初始化命令;test expr 是条件布尔表达式,以决定是否执行循环体body,如果是真,则执行循环体,如果假则退出命令。如果表达式真,则在执行循环体后处理next 命令,即next是一个后置命令执行体。
前三个变元可以选择置空,而将相应的处理放到循环体body中去。
语法:
for {start} {test expr} {next} {
body
}
例如:
#!/usr/bin/tclsh
for {set i 0} { $i < 10 } { incr i 2 } {
if { $i == 4 } {
continue ##如果是4 忽略后面循环体的内容而执行洗一次循环,所以4的值不打印
}
puts "i = $i"
if { $i >= 8 } {
break ##立刻从循环体退出
}
}
执行结果:
[Angel@linux~]$ ./test.tcl
i = 0
i = 2
i = 6
i = 8
switch命令通过将给定字符串与不同的匹配模式进行匹配从而选择执行多分支命令体。switch可基于模式匹配。命令格式为:
switch [option] string {
pattern-1 {body1}
pattern-2 {body2}
…
pattern-n {bodyn}
}
说明:
例如:
#!/usr/bin/tclsh
set result TRUE
switch -wxact -- $result {
"TRUE" {
puts "True"
}
"FALSE" {
puts "FALSE"
}
"UNKNOW" -
default { puts "nnknow or UNKNOW value"}
}
执行结果:
[Angel@linux~]$ ./test.tcl
True
catch命令有两个元素,com_proc是命名体,res用来保存命令返回结果,或是出错时的错误信息,此变元为可选项。如果有错,catch返回1,无错返回0,命名体需要用花括号括起来。
[语法] catch {com_proc} ? res ?
error命令报告错误信息并终止脚本执行。
message_string是错误信息字符串,info变元用于初始化全局变量errorInfo,如果info没有提供,则error自身初始化errorInfo。变元code指定了一个机器可读的错误信息,会被存储在全局变量errorCode中,默认为NONE。
[语法] error message_string ? info ? error_code?
例如:
#!/usr/bin/tclsh
proc enum {} {
error "1.Function enum report error" "2. Some error in function enum" 20
}
catch {enum} str #用catch捕获错误信息,error输出的错误信息被保存在str中
puts "$str"
puts "$errorInfo" #显示errorInfo内的内容
puts "$errorCode" #显示errorCode的值,为error报告的code值
[Angel@linux~]$ ./test.tcl
1.Function enum report error
2. Some error in function enum
(procedure "enum" line 1)
invoked from within
"enum"
20
return命令用来返回调用。return的位置可以根据各种条件和需要进行安排,而且一个过程中可以包含多条return命令,但当遇到第一个可执行的return命令时就返回。
exit命令用来终止脚本的执行。exit会终止并退出整个运行脚本的进程(退出Tcl shell),使用时要小心。如果在退时提供了一个整数数值,则它代表退出状态。
proc命令有三个参数,procName是定义的过程名字;{var1 var2 …}是输入、输出参数列表;body是过程执行命令体。body的界定大括弧和if等命令的命令执行体遵循相同的规则和注意事项。
【语法】 proc procName { var1 var2 … } {
body
}
#!/usr/bin/tclsh set a 10 set b 7 proc test1 { a b } { set c [expr $a*$b] puts "c = $c" } proc test2 {args} { #定义一个只接收可变数目参数的过程 puts "input value are: $args" array set inArr $args parray inArr } test1 5 6 test2 #没有给定任何值 test2 -hostname "Angel" -ip "192.168.1.1" -date "2022.03.09" #给定一组参数值
执行结果:
[Angel@linux~] ./test.tcl
c = 30
input value are:
input value are: -hostname Angel -ip 192.168.1.1 -date 2022.03.09
inArr(-date) = 2022.03.09
inArr(-hostname) = Angel
inArr(-ip) = 192.168.1.1
对于变量而言,分全局变量和局部变量。在所有过程之外定义的变量为外部变量,即全局变量,它的作用域为从开始定义到执行结束,除非中间有显式取消其定义。在一个过程体内定义的变量为内部变量,即局部变量,局部变量的作用域只限于过程内部使用,在此过程外面不能使用这些变量。
在一个过程内部,即可以使用自身的局部变量,又可以使用
全局变量,但是全局变量在过程内部不会自动可见,需要通过global 命令来事先声明。因为作用域不同,所以过程中的变量可以与全局变量、其他过程中的变量有相同的名字。
设置必要的全局变量可以为过程之间提供数据联系的一个渠道。因为全局变量可以供所有过程使用,所以如果在一个过程中改变了全局变量的值,就能影响到其他过程。
在过程定义中的输入、输出参数列表中的参数为过程的内部参数。
例如:
global 命令使全局变量var_3对过程可见。全局变量的定义不一定要在过程外完成,可以在任何一个过程中完成,其效果是将一个局部变量的作用域进行了扩展。但是在引用全局参数的值之前全局参数应首先已被赋值。另外当一个过程中要使用与局部变量相同名字的参数时,用global 命令就要小心:你不能在定义完成一个局部变量后再用global 命令使用同名的全局参数,这会出错。
#!/usr/bin/tclsh set var_1 55 set var_2 aa set var_3 cc proc test3 { a } { set var_2 hello global var_3 puts "Value of input parmeter var_1 is $a" puts "My var_2 is $var_2" puts "Global var_3 is $var_3" } proc test4 {} { global var1 set var1 100 puts "var1 = $var1" } proc test5 {} { global var2 puts "var2 = $var2" } proc test6 {} { set var3 30 global var3 puts "var3 = $var3" } test3 test4 puts "*******test proc for test5*******" test5 puts "*******test proc for test6*******" test6
执行结果:
[Angel@linux~] ./test.tcl Value of input parmeter var_1 is var_1 My var_2 is hello Global var_3 is cc var1 = 100 *******test proc for test5******* can't read "var22": no such variable while executing "puts "var2 = $var2"" (procedure "test5" line 3) invoked from within *******test proc for test6******* variable "var3" already exists while executing "global var3" (procedure "test6" line 3) invoked from within "test6" (file "./test.tcl" line 196)
upvar命令是通过"引用"来使上层过程中的变量,他传递的是参数名而非值。语法如下:
【语法】:upvar ? level ? otherVar1 ?myVar1 ? otherVar2 ? myVar2…?
upvar命令将myVar1定义为otherVar1的一个引用(reference),otherVar是由level 指定的本过程调用栈中的向上level 层的变量。当定义好之后,本过程就可以通过myVar参数来使用otherVar参数。
#!/usr/bin/tclsh proc SetPositive { varname varvalue} { upvar $varname myvar #为输入参数名定义引用为myvar if { $varvalue <0 } { set myvar [expr - $varvalue] } else { set myvar $varvalue } return $myvar } set x 5 set y -5 puts "Before call SetPositive: x = $x, y = $y." SetPositive x $x #调用转换函数处理变量x SetPositive y $y #调用转换函数处理变量y puts "After call SetPositive: x = $x, y = $y."
[Angel@linux~]$ ./upvar.tcl
Before call SetPositive: x = 5, y = -5.
After call SetPositive: x = 5, y = 5.
rename命令 可以用来更改命令名,这些命令名包括tcl自带的内建命令和读者自己定义的过程。
【语法】:rename oldFuncName newFuncName
例如:
#!/usr/bin/tclsh
proc oldname {} { #定义一个过程
puts "This is old function name."
}
oldname
rename oldname newname
puts "###After rename function name###"
newname #调用新的Function Name 打印输出
puts "###Cancel New function name###"
rename newname {} #通过rename取消newname命令
newname #再次调用newname发现命令已经不存在,调用失效
[Angel@linux~]$ ./rename.tcl
This is old function name.
###After rename function name###
This is old function name.
###Cancel New function name###
invalid command name "newname"
while executing
"newname"
(file "./upvar.tcl" line 28)
命令行参数是Tcl shell被调用时定义/初始化的。命令行参数有:
#!/usr/bin/tclsh
puts "The number of command line arguments is: $argc"
puts "The name of the scriptis: $argv0"
puts "The command line arguments are: $argv"
[Angel@linux~]$ ./arg.tcl
The number of command line arguments is: 0
The name of the scriptis: arg.tcl
The command line arguments are:
[Angel@linux~]$ ./arg.tcl a b c d e
The number of command line arguments is: 5
The name of the scriptis: arg.tcl
The command line arguments are: a b c d e
TCL提供了一事先就定义好的全局环境变量数组,这个数组叫做env。
#!/usr/bin/tclsh
puts "$env(PATH)"
#用parray命令打印和显示所有环境变量和变量值
parray env
#加入一条新的条目到PATH中
set env(PATH) "$env(PATH):/usr/sbin"
puts "$env(PATH)"
[Angel@linux~]$ ./env.tcl /usr/local/bin:/bin:/depot/VNC/sun/bin:/usr/ccs/bin:/usr/sbin:/usr/bin:/usr/ucb:/etc:/usr/X/bin:/u/xiaoxue/bin:/u/regress/INFRA_HOME/bin:/depot/perforce:/depot/tools/ccollab/bin:/usr/lib64/qt3.3/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/sbin:/usr/local/bin:/opt/Citrix/VDA/bin:.:/u/xiaoxue/.dotnet/tools:/opt/Citrix/VDA/bin nv(CITRIX_CLIENT_IP_ADDR) = 10.133.180.21 env(CITRIX_CLIENT_PROD_ID) = 1 env(CITRIX_DISPLAY) = :120 env(CITRIX_REMOTE_DISPLAY) = linux:120.0 env(CITRIX_SESSION_ID) = 2 env(COLORFGBG) = 15;0 env(CTX_REMOTE_DISPLAY) = linux:120.0 env(CVS_RSH) = ssh env(DBUS_SESSION_BUS_ADDRESS) = unix:abstract=/tmp/dbus-ibHixlgB1q,guid=556671ced232d27a888ebb560ee7709 env(DEPOT_TOOLS_PATH) = /depot/perforce:/depot/tools/ccollab/bin env(DISPLAY) = :120 ... ... /usr/local/bin:/bin:/depot/VNC/sun/bin:/usr/ccs/bin:/usr/sbin:/usr/bin:/usr/ucb:/etc:/usr/X/bin:/u/xiaoxue/bin:/u/regress/INFRA_HOME/bin:/depot/perforce:/depot/tools/ccollab/bin:/usr/lib64/qt3.3/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/sbin:/usr/local/bin:/opt/Citrix/VDA/bin:.:/u/xiaoxue/.dotnet/tools:/opt/Citrix/VDA/bin:/usr/sbin
任何字符串或者列表,只要符合这个标准,都可以被计算和执行。而eval命令就可以完成计算和执行这种字符串或列表命令,从而允许程序可以动态地构造命令。
【语法】: eval var1 ? var2 ? …varN ?
#!/usr/bin/tclsh
set string "Hello World"
set cmd [list puts stdout $string]
puts stdout {Hello World}
eval $cmd
执行结果:
[Angel@linux~]$ ./eval.tcl
Hello World
Hello World
用clock命令可获得当前系统时间,并能根据指定的格式处理时间字符串。clock相关命令如下表:
clock clicks 返回高分辨率系统时钟计数器值,一般仅用于测量经过的时长。click分辨率取决于系统本身。如果使用了-milliseconds选项,则分辨率以毫秒为粒度。如下面的代码计算出若干秒之内时钟滴答次数:
#!/usr/bin/tclsh
proc click {period} {
set t1 [clock clicks]
#Wait for $period seconds
after [expr $period * 1000]
set t2 [clock clicks]
puts "[expr ($t2 - $t1)/$period] Clicks/Second"
}
click 10
set t3 [clock seconds]
puts "$t3"
[Angel@linux~]$./clock.tcl
000661 Clicks/Second
1646879795
clock format命令将整型时间值格式化为一个可读的日期字符串。这个时间值可以是clock seconds、clock scan命令,或者是带选项atime、mtime和ctime的file命令的返回值。日期字符串的格式可以由-format后的格式化字符串string确定。格式化字符串中使用一个或多个域描述符。域描述符由%后跟一个域描述符字符组成。有效的域描述符如下表所列:
注意:如果没有指定-format , 默认format string “%a %b %d%H:%M:%S %Z %Y” .
#!/usr/bin/tclsh
set Time [clock format [clock second]]
puts "$Time"
set Time1 [clock format [clock second] -format %T]
puts "$Time1"
#clock scan命令用来解析一个日期字符串并返回对应的时间值(以秒为单位)。此命令可
#以处理各种格式的日期,如果没有指明年份,则采用当前年份。
set Time2 [clock format [clock scan "1 week ago"]]
puts "$Time2"
执行结果:
[Angel@linux~]$ ./time.tcl
Thu Mar 10 10:46:27 CST 2022
10:46:27
Thu Mar 03 00:00:00 CST 2022
info命令允许Tcl 程序从Tcl 解释器获得有关当前解释器状态的信息。比如,通过info的子命令可以知道某个过程、变量或者命令是否在当前的解释器中存在,这样你就可以在使用一个变量或者调用一个过程的时候,先测试一下变量或者过程是否存在,从而避免操作不存在的变量、过程或命令而引起的错误。
#!/usr/bin/tclsh proc fact {val} { set level [info level] puts "Current level: $level, val : $val" if { $level == $val} { return $val } set num [expr $val - $level] #将val值减去当前level值 return [expr $num *$val] #返回相乘之后的结果 } set res [fact 3] puts "$res" #info exits 命令可以测试一个变量是否存在。在使用一个变量之前,用此命令先检测一下变 #量是否已经存在,从而避免因为使用了未定义的变量引起的错误。 set a [info exists b] puts "$a" #1:参数b存在 0:参数b不存在
[Angel@linux~]$ ./info.tcl
Current level: 1, val : 3
6
1
trace命令用于变量操作跟踪,它注册一条命令到一个变量,只要这个变量发生指定的变化,如被读、写或者复位(unset)的时候,注册命令就会被调用来进行相关的处理。
[语法] : trace variable varName operations command
说明:
1.operations为变量操作选项,为下列选项的一个或者多个:
2.command为注册命令,它必须能够接收三个参数(。当变量发生operations中的某一个动作的时候,command就会执行:
command var1 var2 var3
其中,var1代表变量名或者数组名。var2是数组元素索引,如果跟踪的是普通变量(非数组变量),或者跟踪的数组被设置为复位跟踪且数组已经被复位,则此参数为空。var3是跟踪的动作,即满足options定义的某个选项对应动作。
3.可以多次调用trace variable为同一变量注册多条命令,这些命令会在指定条件满足时顺次执行。比如可以为一个变量的读、写和复位不同操作分别注册不同的命令,也可以为同一个操作注册多条命令。
#!/usr/bin/tclsh proc traceP1 {args} { puts "---Enter proc traceP1---" puts " There are [llength $args] input variables for trace command" puts "The input three variables' value are:" set varName [lindex $args 0] set index [lindex $args 1] set action [lindex $args 2] puts " varName: $varName \n index: $index \n action: $action" puts "---Proc traceP1 end---" } proc traceP2 {varName arrIndex op} { puts "---Enter proc traceP2---" switch -exact -- $op { w {set option "setted"; } r {set option "read"} u {set option "unsetted"} } puts " Three input variables's values are: " puts " varName: $varName \n index: $arrIndex \n action: $op" puts "Variable $varName was $option" puts "---Proc traceP2 end---" } set a 1 puts "$a" array set b { one Hello two World } trace variable a rwu traceP1 #为变量a 的读、写与复位注册过程traceP1 trace variable a r traceP2 #为变量a的读注册过程traceP2 trace variable b rwu traceP2 #为数组b的读、写与复位注册过程traceP2 trace variable b r traceP1 #为数组b的读注册过程traceP1 puts "$a" puts "$b(one)" # 变量b的读也被注册了两个命令 set a 10 puts "$a" # 变量a的写只被注册了一个命令
[Angel@linux~]$./trace.tcl 1 ---Enter proc traceP2--- Three input variables's values are: varName: a index: action: r Variable a was read ---Proc traceP2 end--- ---Enter proc traceP1--- There are 3 input variables for trace command The input three variables' value are: varName: a index: action: r ---Proc traceP1 end--- 1 ---Enter proc traceP1--- There are 3 input variables for trace command The input three variables' value are: varName: b index: one action: r ---Proc traceP1 end--- ---Enter proc traceP2--- Three input variables's values are: varName: b index: one action: r Variable b was read ---Proc traceP2 end--- Hello ---Enter proc traceP1--- There are 3 input variables for trace command The input three variables' value are: varName: a index: action: w ---Proc traceP1 end--- ---Enter proc traceP2--- Three input variables's values are: varName: a index: action: r Variable a was read ---Proc traceP2 end--- ---Enter proc traceP1--- There are 3 input variables for trace command The input three variables' value are: varName: a index: action: r ---Proc traceP1 end--- 10
从上例可以看出,为变量注册命令后,先执行注册命令,然后在执行对参数的具体操作。用 trace命令还可以作到对变量操作的限制,如可以限制变量为只读变量,当试图对变量进行其他操作时,注册命令就返回错误。
trace vdelete
trace vdelete 删除用trace variable为变量所做的一条注册命令。
[语法]:trace vdelete varName operations command
trace vdelete的语法和trace variable的语法一致。
trace vinfo
trace vinfo返回变量跟踪设置的信息。
Tcl 支持缓存机制的文件I/O操作。最简单的文件操作是gets和puts,但当有大量数据需要读取时,read命令更有效,可以通过read命令将整个文件数据都读出来,然后用split命令将文件按行进行分割。
常用的文件操作命令:open、close、puts、gets、read、seek、tell、eof和flush。
1.open命令
说明:
#!/usr/bin/tclsh if { [catch {open ./data.tcl w+} res ] } { puts "Cannot open ~/data.tcl for write:$res" } else { puts $res "This is one data file." flush $res close $res } proc check_pattern { filename pattern } { set count 0 puts "Search $filename for pattern \"$pattern\"" set fid [open $filename r] #创建文件句柄 while {[gets $fid line] != -1} { #读取文件行 incr count [regexp -all -- $pattern $line] #行号加1 puts "count = $count" #打印行号 } close $fid #关闭文件 if { $count } { puts "Pattern \"$pattern\"found in $filename" #如果检测行中有搜索的$pattern 则打印输出 } return $count } check_pattern data.tcl data
[Angel@linux~]$ ./ioopen.tcl
[Angel@linux~]$ cat data.tcl
This is one data file.
Search data.tcl for pattern "data"
count = 1
count = 2
Pattern "data"found in data.tcl
使用文件命令注意事项:
glob命令和UNIX系统的ls命令相似,用于文件的匹配搜索,并返回一个与搜索模式匹配
的文件名列表。glob支持通配符。
[语法]: glob ?switches? pattern ?patternN?
switches选项有:
glob的匹配模式与string match命令的匹配规则相似:
例子:
#!/usr/bin/tclsh
file lstat la var1
file stat la var2
puts "#######test for var1##########"
parray var1
puts "#######test for var2##########"
parray var2
执行结果:
[Angel@linux~]$ ln -s data.tcl la [Angel@linux~]$ ./ioopen.tcl #######test for var1########## var1(atime) = 1646893421 var1(blksize) = 32768 var1(blocks) = 0 var1(ctime) = 1646893421 var1(dev) = 70 var1(gid) = 31 var1(ino) = 69231190 var1(mode) = 41471 var1(mtime) = 1646893421 var1(nlink) = 1 var1(size) = 8 var1(type) = link var1(uid) = 10040229 #######test for var2########## var2(atime) = 1646891502 var2(blksize) = 32768 var2(blocks) = 0 var2(ctime) = 1646893431 var2(dev) = 70 var2(gid) = 31 var2(ino) = 69231189 var2(mode) = 33188 var2(mtime) = 1646893431 var2(nlink) = 1 var2(size) = 46 var2(type) = file var2(uid) = 10040229
file stat命令数组元素说明:
主要有两中方法在Tcl 中调用一个程序:
用open命令打开一个进程管道:
[语法] open |progName ?access?
progName用双引号括起,可以包含变量,但开始一定是“ |” 。access表明操作选择,有”r”,”w”等,可参见上节的access表。
set fd [open "| sort /etc/passwd" r] #sort命令的标准输出被重定向到文件描述符$fd
puts "Testing for fd $fd"
set str [split [read $fd] \n] #读取管道内的全部信息并以换行符分割
puts "Testing for str $str"
close $fd
[Angel@linux~]$ ./ioopen.tcl
Testing for fd file6
Testing for str adm:x:4:4:Admin:/var/adm: bin:x:2:2::/usr/bin: daemon:x:1:1::/ {listen:x:37:4:Network Admin:/usr/net/nls:} {lp:x:71:8:Line PrinterAdmin:/usr/spool/lp:} {noaccess:x:60002:60002:No Access User:/:} {nobody4:x:65534:65534:SunOS 4.x Nobody:/:} nobody:x:60001:60001:Nobody:/:{nuucp:x:9:9:uucp Admin:/var/spool/uucppublic:/usr/lib/uucp/uucico}
root:x:0:1:Super-User:/:/sbin/sh sys:x:3:3::/: {uucp:x:5:5:uucp Admin:/usr/lib/uucp:} {}
用exec命令调用程序:
[语法] exec ?switches? arg1 ?arg2? … ?argN?
说明:
重定向指示标识说明:
如果没有用&来将exec命令放到后台执行,则该命令在执行期间将被阻塞。
pid命令
pid命令返回当前进程的ID。进程ID在每次进程调用时的值都会改变,所以可以用进程ID作为随机数生成的种子(seed)。也可以通过pid来查出与进程管道相关联的进程ID。
#!/usr/bin/tclsh
set fddd [open "|sort /etc/passwd" r+]
set pidid [pid $fddd]
set currentpid [pid]
puts "thread fd pid = $pidid, current pdi = $currentpid"
[Angel@linux~]$ ./pid.tcl
thread fd pid = 108942, current pdi = 108937
正则表达式的匹配器是用优化的C代码来实现的,因此进行模式匹配的速度很快。
有些Tcl 命令支持正则表达式的操作,比如前面提到的lsearch命令和switch命令都可以支持一个由“ -regexp” 为标志的基于正则表达式匹配操作。此外,还有两个单独的命令来解析正则表达式,它们是regexp和regsub命令。
regexp用来匹配正则表达式和字符串。
【语法】:regexp ? switches ? exp string ? matchvar ? subMatchVar …
subMatchVar?
说明:
选项 | 说明 |
---|---|
-nocase | exp中的小写字符可以匹配string中的大写和小写字符 |
-indices | 返回界定string中匹配区间起始、结束的索引数值。否则返回匹配区间内字符串本身 |
-expanded | 使用扩展语法 |
-line | 等价于同时指定-lineanchor和-linestop |
-lineanchor | 将^和$的行为改为面向行的方式 |
-linestop | 将匹配方式改变成和字符类不匹配换行符 |
-about | 适用于调试,返回有关模式的信息而不是试图与输入进行匹配 |
-all | 让正则表达式在string中匹配所有的匹配子字符串,返回匹配次数,而且将最后一次匹配结果存入匹配变量 |
-inline | 将原来存放在匹配变量中的值以列表的形式返回,如果同时使用了-all,则返回所有满足匹配结果的值的列表。 |
-start index | 用index指定exp在string中起始匹配位置。如果使用了-indices,返回的索引是从输入字符串string的绝对起始位置算起而不是从index指定位置算起 |
- - | 结束选项,如果表达式以-开始, 则需先用此选项 |
#!/usr/bin/tclsh #---------------(1) puts "#---------------(1)" set sample "Whre there is a will, There is a way" puts "$sample" set result [regexp {([a-z]+) ([a-z]+) ([a-z]+)} $sample mStr var1 var2 var3] puts "$result" if { $result } { puts "Result: $result match:$sample:mStr=$mStr;var1=$var1;var2=$var2;var3=$var3" } #---------------(2)带有nocase选项的regexp命令 puts "#--------------(2)" set result [regexp -nocase {([a-z]+) ([a-z]+) ([a-z]+)} $sample matchStr var1 var2 var3] if {$result} { puts "Result: $result match: $sample:\n matchStr=$matchStr;var1=$var1;var2=$var2;var3=$var3" } #-------------------(3) 指明需要返回索引数值而不是字符串本身 puts "#--------------(3)" set result [regexp -indices {([a-z]+) ([a-z]+) ([a-z]+)} $sample mStr var1 var2 var3] if {$result} { puts "Result: $result match: $sample:\n mStr=$mStr;var1=$var1;var2=$var2;var3=$var3" } #-------------------(4) -inline和-all puts "#--------------(4)" set result [regexp -inline -all -- {([a-z]+) ([a-z]+) ([a-z]+)} $sample] puts "result"
执行结果:
[Angel@linux~] ./regexp.tcl
#---------------(1)
Whre there is a will, There is a way
1
Result: 1 match:Whre there is a will, There is a way:mStr=hre there is;var1=hre;var2=there;var3=is
#---------------(2)
Result: 1 match: Where there is a will, There is a way.:matchStr=Where there is;var1=Where;var2=there;var3=is
#---------------(3)
Result: 1 match: Where there is a will, There is a way.:mStr=1 13;var1=1 4;var2=6 10;var3=12 13 #返回的标识匹配区间的索引数值
#---------------(4)
{here there is} here there is {here is a} here is a
regsub命令基于正则表达式完成字符串匹配和替换。
【语法】:regsub ? switches ? exp string subSpec varName
说明:
正则表达式由一个或多个分支(branch)组成,分支之间用符号| 来相连。每个分支则由零个或者多个原子(atom)组成。这些原子的形式主要有(标AREs为AREs支持功能):
大多数字符可以用来直接作为原子和自身进行匹配,如下例中的表达式匹配一个a和b字符组合:
#!/usr/bin/tclsh
regexp {ab} "this text talks about China." match
puts "$match"
regexp {a.} "this text talks about China." match
puts "$match"
执行结果:
[Angel@linux~] ./regexp.tcl
ab
al
字符匹配可以发生在字符串中的任何位置,一个模式不必分配整个字符串,在匹配地字符前面和后面都可以有未匹配的字符。可以使用定位符符(^和 ) 来 指 定 匹 配 位 置 : 将 匹 配 限 制 在 字 符 串 起 始 位 置 , )来指定匹配位置:^将匹配限制在字符串起始位置, )来指定匹配位置:将匹配限制在字符串起始位置,则限制在结尾。可以同时使用这两个符号来匹配整个字符串。如下例匹配所有以字母T或M 开始的字符串:
#!/usr/bin/tclsh
regexp {^[TM]+} "This test talks about Chinese." match
puts "$match"
regexp {^[TM]+} "Man and Woman" match
puts "$match"
regexp {^[T]+} "Hello" match
puts "$match"
执行结果:
T
M
0
通过使用方括号括起多个字符的方式[xyz],来指定匹配字符的范围(1)。这一方法使正则表达式可以对字符集中的任意一个字符进行匹配。
可以使用语法[x-y]来指定从字符x 到字符y的字符组成的字符集(2),这个时候要注意,不同的范围不能共享相同的端点,比如[a-e-z]就是错误的语法。字符集范围对字符排序顺序有较强的依赖性,易于移植的程序要尽量避免使用这样的语法。
还可以用语法[^ xyz]来指定字符集合的补集,即匹配字符为指定字符集以外的任意字符(3)。
#!/usr/bin/tclsh
regexp {[Hh]ello} "He said hello to me." match
puts "$match"
regexp {[Hh]ello} "He said Hello to me." match #等价于[H|h]
puts "$match"
regexp –indices {-[a-dA-D]} “Effort is applied” match #匹配a 到d和A到D之间的任意一个字符,将匹配位置放入match
puts "$match"
regexp -all -inline {[^a-dA-D]} "Effort is applied" #匹配所有非a到d和A到D的字符
执行结果:
[Angel@linux~] ./regexp.tcl
hello
Hello
10 10
E f f o r t {} i s {} P P l i e
一个原子后面可以跟一个量词,来指定进行多次匹配。
例如:
这几个量词具有贪婪(greedy)的特性:它们尽可能多的匹配字符。ARE中增加了非贪婪
(non-greedy)匹配。在使用量词*和?的时候要特别小心,它们可以表示零个。因为零个的所有东西都可以匹配成功。
除了反斜杠字符序列,高级正则表达式还支持字符类匹配,字符类就是利用一个单词代表复杂意思,大部分的字符类与反斜杠序列含义相同,但也有一些字符类是特有的,比如匹配16进制字符的xdigit,几乎所有情况下只要使用字符类就必须将它们放在[[: :]]符号中,下面的表格列出了所有字符类:
扩展的正则表达式语法
扩展语法中,我认为最为重要和方便的就是{}语法,它可以精确指定前面模式匹配的次数,{}语法有3种基本使用方法:
{m} 匹配前面模式的m次
{m,} 匹配前面模式最少m次,最多无限次
{m,n} 匹配前面模式最少m次,最多n次
在实际使用时还可以在{}语法后面加上 ? 号表示非贪婪匹配。
#!/usr/bin/tclsh set dumpout {17:14:24.927839 arp who-has 10.11.105.254 tell 10.11.105.10217:14:24.927936 arp reply 10.11.105.254 is-at 00:13:72:35:a6:fd} set pattern {arp reply 10.11.105.254} set st [regexp -- $pattern $dumpout match] puts $match # set pcarp { Address HWtype HWaddress Flags Mask Iface 10.11.105.29 (incomplete) eth0 10.11.105.19 ether 00:11:D8:35:13:84 C eth0} set pattern {(10.11.105.29)+?.*?incomplete+?} set patt "/u000A*/u000D*" regsub -all -- $patt $pcarp {} pcarp set st [regexp -- $pattern $pcarp match] puts $match
执行结果:
[Angel@linux~] ./regexp.tcl
arp reply 10.11.105.254
10.11.105.29 (incomplete
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。