TCL(tool command language) ,一种解释执行的脚本语言。
TCL语法是一些TCL解释器怎样对TCL命令进行分析的规则的集合
set x 10;
set y x + 10
如果我们想告诉TCL解释器我们期望用x的值10而不是x这个字符,就需要用到置换:TCL提供三种形式的置换,变量置换、命令置换、反斜杠置换,每种置换都会导致一个或多个单词本身被其他值所代替,置换可以发生在包括命令名的每一个单词中,而且置换可以嵌套。
set x 10;
set y $x+10; #y的值为10+10
set x 10;
set y [expr $x + 10];
当TCL解释器遇到字符[时,就会把随后的expr当做一个命令名,从而激活与expr对应的C/C++过程,并把后面的参数传递给该命令过程进行处理。
[ ]中必须是一个合法的TCL脚本,长度不限,[ ]中脚本的值为最后一个命令的返回值,如:
set x 10;
set y [expr $x + 10; set b 100]; #y的值为100,因为 set b 100 的返回值是100
set x muti\ space;
如果不加\,会报错,TCL解释器会认为muti和space是set命令的两个参数。
常用反斜杠置换:
转义序列 | 替换为 |
---|---|
\ddd | 八进制 ,转换为对应的ASCII码 |
\xhh | 十六进制 ,转换为对应的ASCII码 |
\newline space | 连接下一行 |
例如:
set x \111; #I
set y \x48; #H
set z [ expr \
2 + 3]; #5
set a 10 #love 报错:会被当做命令的参数
set a 10 ; #love ;代表一个命令的结束,后面是下一个命令的期望位置
set a 5
set a.1 10;
set b $a.1;
puts $b;#5.1
我们想把a.1这个变量的值赋给b,但是TCL解释器在分析置换变量时,只把从置换变量$后到第一个不是字母数字下划线之前的单词作为变量名字,然后.1字符串紧随其后。
如果即要用置换符$又要变量名中含有非数字字母下划线,可以用{} 将变量名括起来:
set a.1 10;
set b ${a.1};
puts $b;#10
set day(monday) 1;
set day(tusday) 2;
数组元素的置换:
set x $day(monday);
set a tusday;
set y $day($a);
unset a day(monday) day;
list是TCL中表示集合的,TCL中list是由一堆元素组成的有序集合,list可以嵌套定义,list的每个元素可以是任意字符串,也可以是list,下面都是合法的list:
{};
{1 2 3}
{1 2 {1 2} 3};#可以嵌套
TCL提供了很多基本命令对list进行操作。
list 1 2 3 {1 2};#嵌套定义
lrange {2 3 4 {1 2}} 1 end;#3 4 {1 2}
if while for foreach switch break continue
if {$x < 0}{
...
}elseif{$x == 1}{
...
}else{
}
set b {};
set a {1 2 3 4 {1 2} 5}
set i 5;
while { $i>=0 } {
lappend b [lindex $a $i];
incr i -1;
}
puts $b;#attention : lappend + varname / lindex + list; while后命令都用空格隔开
set b {};
set a {1 2 3 4 {1 2} 5};
for { set i 5 } { $i >= 0 } { incr i -1 } {
lappend b [lindex $a $i]
}
puts $b;# {} 之间也要用空格隔开
set b {};
set a {1 2 3 4 {1 2} 5};
foreach i $a {
lappend b $i;
}
puts $b;
foreach varlist list1 varlist2 list2 …
set x {}
foreach {i j} {a b c d e f} {
lappend x $j $i
}# b a d c f e三次循环
set x {}
foreach i {a b c} j {d e f g} {
lappend x $i $j
}# 四次循环 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
}# 3次循环a d e b f g c {] {}, {j k} 为varlist
set x 5;
switch $x {
1 -
2 -
5 {incr x}
default {incr x}
}
puts $x
options 有-exact -glob -regexp,pattern后的-表示和下一个模式操作一样。default匹配任意值。
类似C中的函数,定义自己的TCL命令
proc add {x y} {return [expr $x + $y]}
set a [add 1 2];
puts $a
第一个参数是proc名字,第二个参数是proc的参数列表,变量用空格隔开,第三个参数是一个TCL脚本,代表过程体。可以像调用固有命令一样调用proc命令。还可以return
set b 10;
proc add {x} {
global b;
return [expr $b + $x]
}
set a [add 1];
puts $a
proc add {x {y 2} {z 3}} {
return [expr $x + $y + $z]
}
set a [add 1];
puts $a
args表示吸收其余参数到一个list中,如果没有,args为一个空串。
proc add {x args} {
set sum $x;
foreach i $args {
incr sum $i;
}
return $sum;
}
set a [add 1 2 3];
puts $a
proc add {x} {
upvar $x b;
return [ incr b ];
}
set a 10;
add a ;
puts $a;# 11 attention : upvar 第一个othervar 需要转义
upvar 2 other x
这个命令使当前过程的调用者的调用者中的变量other,在当前过程中可以用x访问,缺省为1,对比第一个例子。如果要访问全局变量:
upvar #0 other x;#此时不论过程处于调用栈的什么位置,都可以在此过程对全局变量other访问
因为TCL把所有输入都当做字符串,所以TCL提供了较强的字符串操作功能,与之有关的命令有:string format regexp regsub scan.
set name gary;
set age 20;
set out [format "%s is %d years old" $name $age];
puts $out;#gary is 20 years old
scan "he is 1 dog" "he is %d dog" a;
puts $a;#scan中a不是引用
字符 | 意义 |
---|---|
. | 匹配任意单个字符 |
^ | 匹配行首 |
$ | 匹配行尾 |
\x | 匹配字符x,抑制x的含义 |
[chars] | 匹配字符集合chars中给出的任意字符,如果chars中第一个字符是^,表示不匹配chars中所有字符,chars表示方法支持a-z之类的表示 |
(regexp) | 把regexp作为单项匹配 |
* | 对前面的项进行0次或多次匹配 |
+ | 对前面的项进行1次或多次匹配 |
? | 对前面的项进行0次或1次匹配 |
regexp1 | regexp2 | 匹配1或2中的一项 |
set a 0x1234;
set b [ regexp {0x[0-9a-fA-F]+} $a];
puts $b;# 1
如果string后有matchvar或者submatchvar,第一个matchvar存整个匹配结果,submatchvar分别存子匹配结果。
set a 0x1234apple;
set b [ regexp {(0x[0-9]+)([a-z]+)} $a x y z];
puts "$x $y $z";#0x1234apple 0x1234 apple
regexp 还可以设置开关:switchs 控制匹配结果
-nocase 不考虑大小写
-indices 改变变量的值,使各变量的值变成对应匹配子串在整个字符串中的索引:
set a "~ 0x1234apple";
set b [ regexp -indices {(0x[0-9]+)([a-z]+)} $a x y z];
puts "$x $y $z";#2 12 2 7 8 12
-about 返回正则表达式本身的信息,而不是对缓冲区的解析,返回一个list,第一个是子表达式个数,第二个存放子表达式的信息。
set a "~ 0x1234apple";
set b [ regexp -about {(0x[0-9]+)([a-z]+)} $a x];
puts "$b";#2 REG_UUNPORT
-expanded 启用扩展规则,将空格和注释忽略,相当于内嵌语法(?x)
-line 启用行敏感匹配,正常情况下^和$只能匹配缓冲区起始和末尾,对于缓冲区内部新的行是不能匹配的,通过这个开关可以匹配缓冲区内新的行,相当于同时使用-linestop 和 -lineanchor,相当于内嵌语法(?n)
-linestop 启动行敏感开关,使^可以匹配缓冲区内部的新行,相当于(?p)
-lineanchor 改变^ 和 $ 匹配行为,可以匹配缓冲区的新行,相当于(?w)
-all尽最大可能匹配
-inline 把匹配结果:整个匹配结果和所有子匹配结果存入list返回
set a "0x1234apple";
set b [ regexp -inline {(0x[0-9]+)([a-z]+)} $a];
puts "$b";#0x1234apple 0x1234 apple
set b [ regexp -inline -all -- {\w(\w)} "abcdef" ];
puts $b;#ab b cd d ef f
– 代表后面再没有switches,都被当做正则表达式
set a "0x1234apple";
set b jjk;
set b [ regsub {(0x[0-9]+)} $a $b c];
puts "$c";#jjkapple
regsub中的开关:
\nocase 同regexp
-all 没有这个开关,regsub只替换第一个匹配,有了这个开关,把所有匹配的地方都替换。
–同regexp
proc tgrep { pattern filename } {
set f [ open $filename r ];
while { [gets $f line ] } {
if { [ regexp $pattern $line ] } {
puts stdout $line;
}
}
close $f;
}
输入匹配模式和文件名,输出匹配的所有行。
access | 方式 |
---|---|
r | 以只读方式打开文件,文件必须已经存在,这是默认方式 |
r+ | 读写方式打开,文件必须存在 |
w | 只写方式打开,如果文件存在则清空文件内容,否则创建新的文件 |
w+ | 读写方式打开,如果文件存在则清空文件内容,否则创建新的文件 |
a | 只写方式打开文件,文件必须已经存在,并把指针指向文件尾,相当于追加模式 |
a+ | 读写,追加,文件不存在则创建 |
seek fileid 2000;#改变fileid文件的访问点,以便下次读写开始于文件的第2000个字节。
origin说明偏移量从哪里开始计算,current是偏移量从当前访问位置计算。
glob *.c *.h# main.c hash.c hash.h
glob还允许模式中包括在花括号中间以逗号分开的多种选择,例如:
glob { {src,backup}/*.[ch]};#src/main.c src/hash.c src/hash.h backup/hash.c
上面命令和下面等价:
glob {src/*.[ch]} {backup/*.[ch]}
file命令是有许多选项的常用命令,可以用来进行文件操作也可以检索文件信息
后续是错误和日志一系列的问题,比较枯燥,待定吧。