标题：TCL语言
基本概念
Tcl (最早称为“工具命令语言”"Tool Command Language", 但是目前已经不是这个含义，不过我们仍然称呼它为TCL)是一种 脚本语言。 由John Ousterhout创建。 TCL很好学，功能很强大。TCL经常被用于 快速原型开发,脚本编程， GUI和测试等方面。TCL念作“踢叩” "tickle". Tcl的特性包括:
* 任何东西都是一条命令，包括语法结构(for, if等)。
* 任何事物都可以重新定义和重载。
* 所有的数据类型都可以看作字符串。
* 语法规则相当简单
* 提供事件驱动给Socket和文件。基于时间或者用户定义的事件也可以。
* 动态的域定义。
* 很容易用C, C++,或者Java扩展。
* 解释语言，代码能够动态的改变。
* 完全的Unicode支持。
* 平台无关。Win32, UNIX, Mac 上都可以跑。
* 和Windows的GUI紧密集成; Tk
* 代码紧凑，易于维护。
TCL本身不提供面向对象的支持。但是语言本身很容易扩展到支持面向对象。许多C语言扩展都提供面向对象能力，包括XOTcl, Incr Tcl 等。另外SNIT扩展本身就是用TCL写的。
使用最广泛的TCL扩展是TK。 TK提供了各种OS平台下的图形用户界面GUI。连强大的Python语言都不单独提供自己的GUI，而是提供接口适配到TK上。另一个流行的扩展包是Expect. Expect提供了通过终端自动执行命令的能力，例如(passwd, ftp, telnet等命令驱动的外壳).
具体例子
下面是TCL程序的例子：
#!/bin/sh
# next line restarts using tclsh in path \
exec tclsh ${1+"$@"}
# echo server that can handle multiple 
# simultaneous connections.
proc newConnection { sock addr port } {
# client connections will be handled in
# line-buffered, non-blocking mode
fconfigure $sock -blocking no -buffering line
# call handleData when socket is readable
fileevent $sock readable [ list handleData $sock ]
}
proc handleData {
puts $sock [ gets $sock ]
if { [ eof $sock ] } {
close $sock
}
}
# handle all connections to port given
# as argument when server was invoked
# by calling newConnection
set port [ lindex $argv 0 ]
socket -server newConnection $port
# enter the event loop by waiting
# on a dummy variable that is otherwise
# unused.
vwait forever
另外一个TK的例子 (来自 A simple A/D clock) 它使用了定时器时间，3行就显示了一个时钟。
proc every {ms body} {eval $body; after $ms [info level 0]}
pack [label .clock -textvar time]
every 1000 {set ::time [clock format [clock sec] -format %H:%M:%S]} ;# RS
解释：第一行定义了过程every， 每隔ms毫秒，就重新执行body代码。第二行创建了标签起内容由time变量决定。第3行中设置定时器，time变量从当前时间中每秒更新一次。 
Tcl被广泛的用做script语言，大多数情况下，Tcl和Tk(“Tool Kit”)库同时使用，Tk是一系列令Tcl易于编写图形用户接口的命令和过程
Tcl的一个重要特性是它的扩展性。如果一个程序需要使用某些标准Tcl没有提供的功能，可以使用c语言创造一些新的Tcl命令，并很容易的融合进去。正是由于Tcl易于扩展，很多人为它编写了扩展包，并在网上共享。
Tcl和其他编程语言例如c不同，它是一种解释语言而非编译语言。Tcl程序由一系列Tcl命令组成，在运行时由Tcl解释器解释运行。解释运行的一个优点是它可以自己为自己生成Tcl script。
变量和变量交换
不像c，Tcl的变量在使用前不需要声明。Tcl的变量在它首次被赋值时产生，使用set命令。变量可以用unset命令删除，虽然并不强制需要这样做。
变量的值通过$符号访问，也叫变量交换。
Tcl是一个典型的”弱类型定义”语言，这意味者任何类型可以存储在任何变量中。例如，同一个变量可以存储数字，日期，字符串甚至另一段Tcl script.
Example 1.1:
set foo "john"
puts "Hi my name is $foo"
Output: Hi my name is john
Example 1.2:
set month 2 
set day 3 
set year 97 
set date "$month:$day:$year" 
puts $date
Output: 2:3:97
Example 1.3:
set foo "puts hi" 
eval $foo
Output: hi
在这个例子里，变量foo存储了另外一段Tcl script.
表达式
包括数学表达式，关系表达式，通常用 expr命令。
Example 2.1:
expr 0 == 1
Output: 0
Example 2.2:
expr 1 == 1
Output: 1
两数比较，true则输出1，false输出0
Example 2.3:
expr 4 + 5
Output: 9
Example 2.4:
expr sin(2)
Output: 0.909297
命令传递
以运算结果替代Tcl命令中的部分
Example 3.1:
puts "I am [expr 10 * 2] years old, and my I.Q. is [expr 100 - 25]"
Output: I am 20 years old, and my I.Q. is 75
方括号是命令传递的标志
Example 3.2:
set my_height 6.0 
puts "If I was 2 inches taller, I would be [expr $my_height + (2.0 / 12.0)] feet tall"
Output: If I was 2 inches taller, I would be 6.16667 feet tall
命令流控制
Tcl有判断流转(if-else; switch)和循环控制(while; for; foreach)
Example 4.1:
set my_planet "earth" 
if {$my_planet == "earth"} {
puts "I feel right at home."
} elseif {$my_planet == "venus"} {
puts "This is not my home."
} else {
puts "I am neither from Earth, nor from Venus."
} 
set temp 95
if {$temp < 80} {
puts "It's a little chilly."
} else {
puts "Warm enough for me."
} 
Output: 
I feel right at home.
Warm enough for me.
Example 4.2:
set num_legs 4
switch $num_legs {
2 {puts "It could be a human."}
4 {puts "It could be a cow."}
6 {puts "It could be an ant."}
8 {puts "It could be a spider."}
default {puts "It could be anything."}
} 
Output: 
It could be a cow.
Example 4.3:
for {set i 0} {$i < 10} {incr i 1} {
puts "In the for loop, and i == $i"
}
Output: 
In the for loop, and i == 0
In the for loop, and i == 1
In the for loop, and i == 2
In the for loop, and i == 3
In the for loop, and i == 4
In the for loop, and i == 5
In the for loop, and i == 6
In the for loop, and i == 7
In the for loop, and i == 8
In the for loop, and i == 9
Example 4.4:
set i 0
while {$i < 10} {
puts "In the while loop, and i == $i"
incr i 1
}
Output: 
In the while loop, and i == 0
In the while loop, and i == 1
In the while loop, and i == 2
In the while loop, and i == 3
In the while loop, and i == 4
In the while loop, and i == 5
In the while loop, and i == 6
In the while loop, and i == 7
In the while loop, and i == 8
In the while loop, and i == 9
Example 4.5:
foreach vowel {a e i o u} {
puts "$vowel is a vowel"
}
Output: 
a is a vowel
e is a vowel
i is a vowel
o is a vowel
u is a vowel
Procedures
参数定义方法
Tcl的Procedures 和c的函数差不多. 它们有参数，它们返回值。基本定义方法是：
proc name argList body
当一个procedure被定义，它就被看做是一个命令，如同Tcl的自带命令一样，通过名字来呼叫，名字后面跟上参数。
缺省的，procedure的返回值是它的最后一个命令结果。但也可以通过return命令来返回其他值。Return值可以在procedure的任何地方，一旦执行，procedure就此返回。
Example 5.1:
proc sum_proc {a b} {
return [expr $a + $b]
} 
proc magnitude {num} {
if {$num > 0} {
return $num
} 
set num [expr $num * (-1)]
return $num
} 
set num1 12
set num2 14
set sum [sum_proc $num1 $num2] 
puts "The sum is $sum"
puts "The magnitude of 3 is [magnitude 3]"
puts "The magnitude of -2 is [magnitude -2]" 
Output: 
The sum is 26
The magnitude of 3 is 3
The magnitude of -2 is 2
在procedure中可以通过set创造变量，但是变量只在procedure中有效，而且一旦procedure返回，这些变量就不可访问。如果procedure需要访问主程序中的变量，就需要使用global关键字。
Example 5.2:
proc dumb_proc {} {
set myvar 4
puts "The value of the local variable is $myvar" 
global myglobalvar
puts "The value of the global variable is $myglobalvar"
} 
set myglobalvar 79
dumb_proc
Output: 
The value of the local variable is 4
The value of the global variable is 79
Lists
Lists就好像是Tcl中的一种特殊的数组。它把一堆东西放成一个集合，然后就像操作一个整体一样的操作它。
Example 6.1:
set simple_list "John Joe Mary Susan"
puts [lindex $simple_list 0]
puts [lindex $simple_list 2]
Output: 
John
Mary
注意list的index是从0开始的
Example 6.2:
set simple_list2 "Mike Sam Heather Jennifer"
set compound_list [list $simple_list $simple_list2]
puts $compound_list
puts [llength $compound_list]
Output: 
{John Joe Mary Susan} {Mike Sam Heather Jennifer}
2
Example 6.3:
set mylist "Mercury Venus Mars"
puts $mylist
set mylist [linsert $mylist 2 Earth]
puts $mylist
lappend mylist Jupiter
puts $mylist
Output: 
Mercury Venus Mars
Mercury Venus Earth Mars
Mercury Venus Earth Mars Jupiter
Arrays
Tcl数组在使用前无须定义，大小也不用指定。 
Example 7.1:
set myarray(0) "Zero"
set myarray(1) "One"
set myarray(2) "Two" 
for {set i 0} {$i < 3} {incr i 1} {
puts $myarray($i)
} 
Output: 
Zero
One
Two
Example 7.2:
set person_info(name) "Fred Smith"
set person_info(age) "25"
set person_info(occupation) "Plumber" 
foreach thing {name age occupation} {
puts "$thing == $person_info($thing)"
} 
Output: 
name == Fred Smith
age == 25
occupation == Plumber
这个例子指出数组的index不需要是数字，其他类型的数据也可以。
Example 7.3:
set person_info(name) "Fred Smith"
set person_info(age) "25"
set person_info(occupation) "Plumber" 
foreach thing [array names person_info] {
puts "$thing == $person_info($thing)"
} 
Output: 
occupation == Plumber
age == 25
name == Fred Smith
Strings
字符串是Tcl中最常用的类型，string有很多使用参数，可以参照Tcl手册。使用方法：
string option arg arg ...
Example 8.1:
set str "This is a string" 
puts "The string is: $str"
puts "The length of the string is: [string length $str]" 
puts "The character at index 3 is: [string index $str 3]"
puts "The characters from index 4 through 8 are: [string range $str 4 8]"
puts "The index of the first occurrence of letter \"i\" is: [string first i $str]"
Output:
The string is: This is a string
The length of the string is: 16
The character at index 3 is: s
The characters from index 4 through 8 are: is a
The index of the first occurrence of letter "i" is: 2
Input/Output
Tcl的绝大多数输入/输出是通过puts和gets做到的。Puts命令显示在console上，gets命令从console输入上取得数据，并存储在某个变量中。
gets channelId varName
channelID可以理解为c的文件句柄，varName如果定义，输入值就赋给它，gets返回读入的字节数，否则gets直接返回输入值。
Example 9.1:
puts -nonewline "Enter your name: "
set bytesread [gets stdin name] 
puts "Your name is $name, and it is $bytesread bytes long" 
Output: (note that user input is shown in italics)
Enter your name: Shyam
Your name is Shyam, and it is 5 bytes long
Example 9.2: 
set f [open "/tmp/myfile" "w"] 
puts $f "We live in Texas. It's already 110 degrees out here."
puts $f "456" 
close $f
Output: (none)
Open打开了一个 "/tmp/myfile" 作为channel. 用法是：
open name access
access参数指出打开文件的方式，”w”是读写。这时可以用puts $f把内容写入文件
Example 9.3: 
set f [open "/tmp/myfile" "r"] 
set line1 [gets $f]
set len_line2 [gets $f line2] 
close $f 
puts "line 1: $line1"
puts "line 2: $line2"
puts "Length of line 2: $len_line2"
Output:
line 1: We live in Texas. It's already 110 degrees out here.
line 2: 456
Length of line 2: 3
这个例子假设已知文件只有两行，如果不是，则需要使用循环，用eof来找到文件尾。
eval
eval命令会把它的参数直接送往解释器。
Example 10.1:
set foo "set a 22"
eval $foo
puts $a
Output:
22
单纯的执行$foo不会成功。
catch
Example 10.2: 
set retval [catch {set f [open "nosuchfile" "r"]}] 
if {$retval == 1} {
puts "An error occured"
}
Output: (this output occurs if there is no file named "nosuchfile" in the current directory).
An error occured
Catch 参数记录一个script的执行情况，如果返回值为1，则执行出错。用来进行错误处理。