TCL語言
TCL語言
Tcl最早稱為“工具命令語言”"Tool Command Language",但是目前已經不是這個含義,不過我們仍然稱呼它為TCL)是一種腳本語言。由John Ousterhout創建。TCL很好學,功能很強大。TCL經常被用於快速原型開發,腳本編程,GUI和測試等方面。
TCL念作“踢叩” "tickle"。Tcl的特性包括:
* 任何東西都是一條命令,包括語法結構(for , if等)。
* 任何事物都可以重新定義和重載。
* 所有的數據類型都可以看作字元串。
* 語法規則相當簡單
* 提供事件驅動給Socket和文件。基於時間或者用戶定義的事件也可以。
* 動態的域定義。
* 很容易用C ,C++ ,或者Java擴展。
*解釋語言,代碼能夠動態的改變。
* 完全的Unicode支持。
* 和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 whensocketis 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 {msbody} {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。
Tcl的Procedures 和c的函數差不多,它們有參數,返回值。基本的定義方法是:
proc name argListbody
當一個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
不像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
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輸入上取得數據,並存儲在某個變數中。
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,則執行出錯。用來進行錯誤處理。