1. 程式人生 > 其它 >tcl語法快速查詢手冊

tcl語法快速查詢手冊

0、教程

https://www.yiibai.com/tcl/tcl_environment.html
或者
https://noyesno.net/page/tcltk/20090719-87.html
或者
https://www.learnfk.com/article-tcl-tk/tk_images
或者
https://www.w3cschool.cn/doc_tcl_tk/tcl_tk-itclcmd-body-htm.html?lang=en
或者
https://blog.csdn.net/xmlbm/article/details/100038912
或者
https://blog.csdn.net/artechtor/article/details/1665930


1、安裝


1)在https://www.activestate.com/products/tcl/downloads 網站下載tcl8.6;
2)雙擊ActiveTcl-8.6.9.8609.2-MSWin32-x64-5ccbd9ac8.exe安裝包;
3)安裝時提示安裝microsoft visual C++ 2015 visual studio update3,下載安裝這個檔案;
4)安裝ActiveTcl-8.6.9.8609.2-MSWin32-x64-5ccbd9ac8.exe安裝包;


2、基本語法


1)語句分隔
;或者newline
如果每個命令都使用換行符,則分號不是必須的;
2)註釋
內聯註釋用;#
puts "Hello World!" ;# my first print in Tcl program
使用#符號註釋單行
# my first program in Tcl

使用條件為0的if寫入多行或塊註釋,;
if 0 {
my first program in Tcl program
Its very simple
}
3)行繼續
\在行尾
% set a [list aa \
bb \
cc ]
aa bb cc
% set a
aa bb cc
4)變數
使用字母、數字、下劃線和$符號組成變數、函式名稱;
大小寫敏感;

5)保留字,不能被用作常量或變數。常見保留字有after、continue、else、catch、file等;
保留字列表:https://www.yiibai.com/tcl/tcl_basic_syntax.html
6)特殊變數,系統內建的變數。常見的有argc、argv、env、tcl_version等;
特殊變數列表:https://www.yiibai.com/tcl/tcl_special_variables.html#article-start
特殊變數 描述
argc 指命令列引數的個數。
argv 指包含命令列引數的列表。
argv0 是指被解釋的檔案或由呼叫指令碼的名稱的檔名。
env 用於表示是環境變數陣列元素。
errorCode 為最後的tcl錯誤的錯誤程式碼
errorInfo 為最後Tcl錯誤的堆疊跟蹤錯誤資訊
tcl_interactive 分別將其設定為1和0互動和非互動模式之間切換
tcl_library 用於設定標準Tcl庫的位置
tcl_pkgPath 提供一般都安裝包的目錄列表
tcl_patchLevel zhideshiTcl解釋目前的補丁級別
tcl_platform 用於表示使用物件,包括byteOrder,machine,osVersion平臺和作業系統陣列元素
tcl_precision 指的是精度,即位數轉換為浮點數時,字串保留。預設值是12.
tcl_prompt1 指的是主提示符
tcl_prompt2 指無效的命令二次提示。
tcl_rcFileName 為使用者提供了具體的啟動檔案。
tcl_traceCompile 用於控制位元組碼編譯的跟蹤。用0表示無輸出,1為概要和2為詳細。
tcl_traceExec 用於控制執行的位元組碼的跟蹤。用0表示無輸出,1為概要和2為詳細。
tcl_version 返回Tcl直譯器的最新版本。
7)替換與不替換
變數替換,用來返回變數的值,例如set a 3;puts $a
命令替換,用來返回命令的值,例如puts [expr 1 + 6 + 9]
" string " 帶替換的引用
{ string } 不帶替換的引用
[ string ] 命令替換
8)tcl命令的語法:commandName argument1 argument2 ... argumentN

3、資料型別


1)整數型別


set myVariable 18
puts $myVariable # 此時myVariable自動轉為字串型別,再輸出
puts [expr $myVariable + 6 + 8] # 此時myVariable轉換為整形,進行數學計算


2)字串型別


set myVariable hello # 單個單詞不需要使用雙引號
set myVariable "hello world" # 多個單詞需要使用雙引號
set s1 "Hello World"
set s2 "o"
讀取某個索引的字元
string index "Hello! " 0;#輸出H
string index "Hello! " end;#輸出!
string index "Hello! " end-4;#輸出e
擷取字串
string range "Sample string" 3 7;#輸出ple s
string range "Sample string" 3 end;#輸出ple string
字串長度
puts [string length $s1]
大小寫轉換
puts [string toupper $s1]
puts [string tolower $s1]
去掉字串兩邊空格
set s1 " hello world "
set s2 " "
puts [string trimright $s1 $s2];#去掉右空格
puts [string trimleft $s1 $s2];#去掉左空格
puts [string trim $s1 $s2];#去掉兩邊空格
合併字串
set s1 "Hello"
append s1 " World"
puts $s1;#輸出“Hello World”
【注意:append命令後的變數s1直接使用,不加$符號,這個命令直接修改s1的值】
拆分字串
puts [split "red_green_blue" _];#輸出red green blue
字串比較
string compare "This is a tcltk example" "This is a TCLTK example";#返回1,因為ASCII碼T在t之後,所以從順序上來說前面的字串顯然在前
string compare "This is a tcltk example" "This is a tcltk example";#返回0,兩個字串相等
string compare "This is a TCLTK example" "This is a tcltk example";#返回-1

string equal "This is a TCLTK example" "This is a tcltk example";#不同返回0
string equal "This is a tcltk example" "This is a tcltk example";#相同返回1
搜尋字串
string first "tcltk" "This is a tcltk example";#返回10,返回第一次匹配的索引,如果找不到則返回-1
string last "is" "This is a tcltk example";#返回5,返回最後一次匹配的索引


替換字串
string map {key1 value1 key2 value3 ...} 1abcaababcabababc;#將1abcaababcabababc中的key1替換為value1,key2替換為value2

3)列表型別


列表是一組元素,使用雙引號或者大括號表示簡單的列表。
set myVariable {red green blue}
set myVariable "red green blue"

|命令 |說明
| |
|list arg1 arg2 ... |建立一個列表
| |
|lindex list index |返回列表 list 中的第 index 個元素(element)值
| |
|llength list |計算列表 list 元素個數
| |
|lrange list index1 index2 |返回指定範圍內(從 index1 到 index2)的元素
| |
|lappend list arg1 arg2 ... |將新元素追加到原來列表 list 後組成新的列表
| |
|linsert list index arg1 arg2 ... |將新元素插入到 list 中位於 index 元素之前的位置上
| |
|lreplace list index1 index2 arg1 arg2 ... |替換指定範圍的元素
| |
|lsearch ?mode? list value |根據匹配模式 mode,查詢 list 中與 value 匹配的元素位置索引。mode 一般為-exact、-glob 和regexp.預設為-glob。找不到返回-1。
| |
|lsort ?switches? list |根據開關選項對列表進行排序
| |
|concat list1 list2 ... |連線多個列表內容成一個列表
| |
|join list joinChars |以 joinChars 為分隔符將列表中的元素合併在一起
| |
|split string splitChars |以 splitChars 中的字元作為分隔符將字串分解為列表元素。
| |
|foreach var list {proc body} |遍歷列表各項,逐次將各元素值存入 var 中並執行 proc body。相當於一個迴圈控制語句。

list命令:用來建立列表。一個列表可以包含子列表,即列表可以巢狀。
set l1 [list Sun Mon Tues]
結果=>Sun Mon Tues

set l2 [list $l1 Wed] ;#列表 l1 含有三個元素
結果=> {Sun Mon Tues} Wed

set str1 "Sun Mon Tues"
結果=>Sun Mon Tues

set l2 [list $str1 Wed] ;#列表 l2 中含有兩個元素。第一個元素用花括號括起來。
結果=>{Sun Mon Tues} Wed ;#和上面的命令結果相同:“列表是特殊的字串”。

concat命令:以空格為分隔符將多個列表拼裝在一起形成新的列表。它和雙引號的作用比較相似。
set x {1 2}
結果=> 1 2

set y "$x 3 " ; #$x 被替換後,作為列表結構的花括號被去掉,
結果=> 1 2 3 ; #元素被提出來和 3 一起作為新列表的元素

set y "$x {3}"
結果=> 1 2 {3}

set y [concat $x 3] ;#結果同上面的雙引號
結果=> 1 2 3

set y [concat $x {3}]
結果=> 1 2 3

lindex命令:返回列表中指定位置的特定元素。列表索引從 0 開始記數!
set x { 1 2 3 }
結果=> 1 2 3

puts [lindex $x 1]
=>2

llength命令:可以獲得一個列表內元素的個數。
set length "1 2 3 4 5"
結果=>1 2 3 4 5 ;#定義了一個字串
set num [llength $l1] ;#這裡 l1 被看作列表了
=>5

lrange命令:返回一個指定區段的列表元素,可以以 end 或者 end-n 作為索引(n 為正整數)。
lrange {1 2 3 {4 5} 6} 2 end
結果=> 3 {4 5} 6

lmap命令:在最簡單的情況下,只有一個迴圈變數varname,和一個列表list,list中的值會依次分配給變數varname,body是一個Tcl指令碼。
lmap varname list body
body所代表的指令碼會使用varname進行處理。
如果主體的執行正常完成,則body的結果追加到累加器列表中,lmap最後返回累加器列表。
如果body中最後一個命令返回值為空,則lmap的返回結果為所有值均為空值的列表。

linsert命令:用來將元素插入到一個列表的由索引指定的位置。如果索引為 0 或者更小,則元素就會被新增到最前面。
如果索引值大於或者等於列表長度,則元素被追加到列表尾部。其他情況元素被新增到指定位置之前。
注意:這個操作不會改變原來列表的內容,而是返回一個新列表。
set x {1 2}
結果=>1 2

set new [linsert $x 0 he she]
結果=>he she 1 2

set new [linsert $x end he she]
結果=>1 2 he she

set new [linsert $x 1 he she]
結果=>1 he she 2

puts $x
結果=>1 2 ;# x 的值沒有改變

puts $new
結果=>1 he she 2

lreplace命令:將一個指定區段的列表元素替換為新元素,
如果沒有指定新元素,則這個區域的元素就會被從列表中刪除。
注意:這個操作不會改變原來列表的內容,而是返回一個新列表。
set new {1 he she 2}
結果=>1 he she 2

set y [lreplace $new 1 2 B C]
結果=>1 B C 2

set y [lreplace $new 0 0]
結果=>he she 2 ;#刪除列表元素,將第 0 個元素刪除

puts $new
結果=>1 he she 2 ;#new 的內容並沒有改變,這和 string replace 相同。

set y [lreplace $new 1 2]
結果=>1 2 ;#將第 1、2 個元素刪除

lsort命令:實現對列表的排序。
注意:排序操作不影響原表,而是返回排序之後的新表。
set list "a Z z n100 n200 M p Hl hL m 1 20"
結果=>a Z z n100 n200 M p Hl hL m 1 20

lsort -ascii $list
結果=>1 20 Hl M Z a hL m n100 n200 p z

lsort -dictionary $list
結果=>1 20 a Hl hL M m n100 n200 p Z z

lsearch命令:與in命令類似。在給定列表中搜索與匹配字串匹配的元素,成功就返回正確的元素索引,否則返回-1。
lsearch 支援萬用字元格式,但可以使用-exact 選項將其遮蔽而進行精確匹配。
set l1 [list This is one list]
結果=> This is one list

set index [lsearch $l1 l*]
結果=> 3

set index [lsearch -exact $l1 l*]
結果=>-1

set index [lsearch -exact $l1 list]
結果=>3

set stripped [lsearch -inline -all -not -exact $inputList $elemToRemove];#刪除元素的另一種方法是將其過濾掉

-all 返回全部匹配項
-inline 返回匹配項的值,而不是索引

concat命令:將連線多個列表
concat a b {c d e} {f {g h}}
將返回結果“a b c d e f {g h}”)
in命令:判斷列表中是否有某個字串
if {orange in $var} {
puts "orange is in var"
}

join命令:接收一個列表,並用指定的分隔符將列表元素整合成一個字串
join {1 {2 3} {4 5 6}} :
結果=> 1:2 3:4 5 6

split命令:作用與 join 的作用相反,它接收一個字串,並根據給定的字元將其分割轉換成
注意:這個操作不會改變原來字串的內容,而是返回一個新列表。
set str cm8/auto/tools/aries/ASAM/NE/SNMP/IMPL/ne_create_board.tcl
結果=>cm8/auto/tools/aries/ASAM/NE/SNMP/IMPL/ne_create_board.tcl
set s /
結果=>/

set l1 [split $str $s]
結果=> cm8 auto tools aries ASAM NE SNMP IMPL ne_create_board.tcl

set l2 [split $str "/."] ;#可以指定多個分割符
結果=> cm8 auto tools aries ASAM NE SNMP IMPL ne_create_board tcl

foreach命令:會遍歷整個列表,逐次取出列表的每個元素的值放到指定變數中,使用者可以在跟隨的過程體中新增必要的處理過程。
set lst "1 2 3 4"
結果是=>1 2 3 4

foreach item $lst {
puts $item
}
結果是=>
1
2
3
4

lappend命令:追加專案到列表末尾
set var orange
lappend var "red"
puts $var;#輸出orange red
【注意:lappend命令後的變數s1直接使用,不加$符號,這個命令直接修改s1的值】
lreverse命令:反轉列表元素的順序
lreverse {a a b c}
-->c b a a
lreverse {a b {c d} e f}
-->f e {c d} b a
用列表項給變數賦值
set var {orange blue red green}
lassign $var colour1 colour2
puts $colour1;#輸出orange
puts $colour2;#輸出blue

按照索引刪除列表元素:參考replace命令
按照值刪除列表元素:參考lsearch命令


4)陣列(array)


set marks(english) 80
puts $marks(english)
set marks(mathematics) 90
puts $marks(mathematics)
% array get marks math
math 90
陣列的大小
puts [array size marks]
【注意:陣列size命令後的變數名不加$符號】
陣列的索引
puts [array names marks]
【注意:陣列names命令後的變數名不加$符號】
使用foreach語句遍歷陣列
foreach index [array names marks] {
puts "marks($index): $marks($index)"
}
# 上面的index是臨時定義的變數


5)布林型別


1,yes 或 true 為真值
0,no 或 false 為假值


6)字典


https://webcache.googleusercontent.com/search?q=cache:ZGvZvFZG-FkJ:https://blog.csdn.net/asty9000/article/details/90217533+&cd=1&hl=zh-CN&ct=clnk
建立字典
set colours [dict create colour3 "black" colour4 "white"]
puts $colours;#輸出colour3 black colour4 white
修改或者新增鍵值對
dict set colours colour1 red
dict set colours colour3 green
puts $colours;#輸出colour3 green colour4 white colour1 red
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% dict set dic f g h 8
a 1 b 2 c 3 f {g {h 8}}
【注:set命令只能每次修改一個鍵值對】
unset
dict unset dictName key ?key ...?
刪除字典dictName中key對應的值。
如果dictName中不存在key,則不進行任何操作。
當存在多個鍵時表示刪除巢狀字典中的元素,此時的鍵路徑上除了最後一個key可以不存在外,
前面的key必須存在,否則會報錯key "xxx" not known in dictionary。
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% dict unset dic c
a 1 b 2
remove
dict remove dictValue ?key ...?
返回一個新的字典【不改變原來字典】,字典包括鍵為key以外的所有dictValue中的鍵值對。
如果不指定任何鍵則返回的字典與dictValue相同,如果key不在dictValue中,則不進行任何操作。
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% dict remove $dic a
b 2 c 3
% puts [dict keys $dic]
a b c
merge
dict merge ?dictValue ...?
返回一個新的字典,包含dictValue中的所有元素,多個dictValue具有相同的key的元素的時,
最後一次出現的key對應的值會出現在新的字典中。
% set newDic [dict merge {a 1 b 2} {c 3 d 4 b 5}]
a 1 b 5 c 3 d 4
字典大小
set colours [dict create colour3 black colour4 white]
puts [dict size $colours];#輸出2
字典某個鍵的值
set colours [dict create colour3 black colour4 white]
puts [dict get $colours colour3];#輸出black
字典中的所有鍵
set colours [dict create colour3 black colour4 white]
set keys [dict keys $colours]
puts $keys;#輸出colour3 colour4
字典中的所有值
set colours [dict create colour3 black colour4 white]
set values [dict values $colours]
puts $values;#輸出black white
字典是否含有某個鍵
set colours [dict create colour3 black colour4 white]
set result [dict exists $colours colour3]
puts $result;#輸出1
字典迭代
set colours [dict create colour3 black colour4 white]
foreach key [dict keys $colours] {
puts [dict get $colours $key]
}
# 分兩行分別輸出black和white
字典遍歷列表
用於遍歷字典dictValue,在執行body中指令碼時,字典中每個鍵值對的鍵和值會分別分配給名為指定的keyName和valueName變數。
dict for命令的結果為空字串。當在body執行過程中遇到break時,會中止迴圈,結束dict for命令。
當遇到continue命令時,會結束本輪迴圈。字典按鍵值對的插入順序進行遍歷。
set colours "colour1 red colour2 white colour3 black"
dict for {key value} $colours {
puts "key:$key,value:$value"
}
append
dict append dictName key ?string ...?
將給定的string追加到字典dictName中鍵key的值後面。
如果key不存在,則相當於新增一個key的對映。
如果未指定string,則視為空字串。
多個string會合併為一個字串。此命令返回更新後的字典。
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
%
% dict append dic ab 4 5
a 1 b 2 c 3 ab 45
% dict append dic a 6
a 16 b 2 c 3 ab 45
%
% dict append dic ab
a 16 b 2 c 3 ab 45

lappend
dict lappend dictName key ?value ...?
將給定的value追加到dictName中指定key對應的列表中,可以同時追加多個value,
如果key對應的值不是列表,會建立一個列表,並將原有值和追加的值放到列表中。
如果key存在,但沒有指定value,則不做任何操作。
如果dictName中不存在key,則視為空列表,若此時value也未指定則會新增一個鍵為key值為空列表的元素,
若指定了value則會將value作為列表的元素。如果key對應的值不能表示為列表則會報錯。
% dict lappend dic a
a 1 b 2 c 3
% dict lappend dic a 1
a {1 1} b 2 c 3
% dict lappend dic e
a {1 1} b 2 c 3 e {}
% dict lappend dic e 1 2 3 4 5
a {1 1} b 2 c 3 e {1 2 3 4 5}
incr
dict incr dictName key ?increment?
將字典dictName中指定key對應的值增加increment。
如果未指定increment,則預設增加1。
如果不存在指定的key,則視為0。如果key對應的值不是整數則會報錯
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% dict incr dic a
a 2 b 2 c 3

dict update dictName key varName ?key varName ...? body
使用對映dictName中key對應的值的變數varName執行body中的指令碼。
如果dictName沒有指定的key,則其對應的變數varname為未設定。
當body終止時,對varName所做的更改都會被會寫到字典內即使body的結果是一個錯誤或其他異常,
除非字典不可讀所有的更新都被靜默的丟棄。
除非發成異常,否則dict update的結果是body的執行結果。
建議只在本地作用域內使用此命令,因為dict update命令中的變數varName在命令完成後,除非顯示的執行unset,否則仍然存在。
此外,只有當body終止時,才會更改dictName中的內容
replace
dict replace dictValue ?key value ...?
返回一個新的字典,包括傳入的dictValue以及一些額外的或不同的鍵值對。
如果不傳如鍵值對key、value,則返回的新字典與dictValue相同。鍵值對必須是成對出現,否則會報錯。
dictValue中存在的key會用心的value替換,不存在的key會新增到新的字典。
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% set newDic [dict replace $dic a 1 b 3 d 4]
a 1 b 3 c 3 d 4


info
dict info dictValue
返回字典資訊,資訊的具體格式取決於字典的實現方式。由於字典是散列表實現的,所以放回結果類似於array statistics命令。
with
dict with dictName ?key ...? body
與update類似,使用dictName中key對應的值執行body中的指令碼。
如果key為多個表示巢狀字典的鍵路徑,此時會使用鍵路徑對應的字典執行body中的指令碼。
字典中key對應的值會對映到與key同名的變數中。
與dict update一樣,如果dictName不可讀或者字典調整導致鍵路徑沒有對應的值,則會靜默丟棄字典的更新。
除非發成異常,否則dict with的結果是body的執行結果。
建議只在本地作用域內使用此命令,因為dict with命令中的變數在命令完成後,除非顯示的執行unset,否則仍然存在。
此外,只有當body終止時,才會更改dictName中的內容。當body終止時如果dictName不是字典則會產生錯誤。
因此當字典中的鍵與字典變數dictName有衝突時不建議使用此命令。
% set info [dict create forenames Joe surname Schmoe street {147 Short Street} city Springfield phone 555-1234]
forenames Joe surname Schmoe street {147 Short Street} city Springfield phone 555-1234
% dict with info {
puts " Name: $forenames $surname"
puts " Address: $street, $city"
puts " Telephone: $phone"
}
Name: Joe Schmoe
Address: 147 Short Street, Springfield
Telephone: 555-1234
filter
dict filter dictValue filterType arg ?arg ...?
返回一個新的與指定過濾型別匹配的鍵值對的字典
有三種過濾方式:按照key過濾,按照value過濾,或者使用指令碼過濾
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% dict filter $dic key a*
a 1
% dict filter $dic value 2*
b 2
% dict filter $dic script {k v} { expr { $k < "e"} }
a 1 b 2 c 3
map
dict map {keyName valueName} dictValue body
Tcl8.6新增的命令。
此命令通過執行body中的命令,對字典dictValue中的鍵值進行轉換,然後返回一個新的包含轉換後的鍵值對的字典。
名為keyName、valueName對應於dictValue中鍵值對的鍵與值。
每次body執行完後,變數keyName、valueName的值即為新字典的鍵值。
當在body執行過程中遇到break時,會中止迴圈,結束dict map命令。
當遇到continue命令時,會結束本輪迴圈。
另外要注意的是,如果不想對值做改變,需要對其進行顯示的set操作,否則值會被設定為body中最後一個命令的返回值。
% set dic [dict create a 1 b 2 c 3]
a 1 b 2 c 3
% dict map { k v } $dic { set k $k$k; set v $v;}
aa 1 bb 2 cc 3

5)控制代碼
控制代碼通常用於檔案、網路請求的處理
set myfile [open "filename" r]


4、數學計算


1)expr用於表示數學表示式,預設精度為12位數;
2)使用tcl_precision特殊變數來更改精度;


5、if語句


if { $a == 10 } {
puts "Value of a is 10"
} elseif { $a == 20 } {
puts "Value of a is 20"
} else {
puts "Exact value of a is: $a"
}
# 注意:else和兩邊的花括號間有空格。

TCL中有4個用於表示式的字串操作符:eq、ne、in、ni.
1)eq和ne用來檢查字串是否相等,如果相等eq返回1,ne返回0,如果不等ne返回1,eq返回0.
2)除了檢查字串相等還是不相等的eq和ne操作符,<、>、<=、>=、==、!=操作符都可以進行字串比較
3)如果指定字串是列表的元素,in操作符返回1,否則返回0.如果字串不是列表的元素,in操作符返回1,否則返回0


6、switch語句


set grade B;

switch $grade {
A {
puts "Well done!"
}
B {
puts "Excellent!"
}
default {
puts "Invalid grade"
}
}
puts "Your grade is $grade"


7、while迴圈


set a 10
while { $a < 20} {
puts "value of a is $a"
incr a;#自增1。也可以指定步長,例如-1,此時每次自減1。
}


8、for迴圈


for { set a 10} { $a < 20 } { incr a } {
puts "value of a is $a"
}


9、過程(也就是函式)


1)無引數過程
proc hello {} {
puts "hello world!"
}
hello;#輸出hello world!
2)多個引數過程
proc add { a b } {
puts [ expr $a + $b ]
}
puts [add 4 5];#輸出9
3)可變引數過程
proc sum { numbers } {
set result 0
foreach number $numbers {
set result [ expr $result + $number ]
}
return $result
【注意:這裡要返回值,不是返回變數】
}
puts [ sum {1 2 3 4 5} ]
4)預設引數
proc add { a {b 100}} {
puts [expr $a + $b ]
}
puts [ add 15 ]
5)遞迴
proc factorial { a } {
if { $a == 1} {
return 1
}
return [expr $a*[factorial [ expr $a - 1 ]]]
}
puts [factorial 3]


10、名稱空間


10.1、建立名稱空間


namespace eval MyMath {
variable myResult
}
proc ::MyMath::add { a b } {
set ::MyMath::myResult [ expr $a + $b ]
}
::MyMath::add 5 6
puts $::MyMath::myResult


10.2、名稱空間巢狀


namespace eval MyMath {
variable myResult
}
namespace eval extendedMath {
namespace eval MyMath {
variable myResult
}
}
set ::MyMath::myResult "test1"
puts $::MyMath::myResult
set ::extendedMath::MyMath::myResult "test2"
puts $::extendedMath::MyMath::myResult


10.3、匯入匯出名稱空間(不必藉助空間名字,直接引用空間內的變數和過程)


namespace eval MyMath {
variable myResult
namespace export Add
}
proc ::MyMath::Add {a b } {
return [expr $a + $b ]
}
namespace import ::MyMath::*
puts [Add 3 4 ]


10.4、忘記名稱空間


namespace eval MyMath {
variable myResult
namespace export Add
}
proc ::MyMath::Add {a b } {
return [expr $a + $b ]
}
namespace import ::MyMath::*
puts [Add 3 4 ]
namespace forget ::MyMath::*
puts [Add 4 5 ];#因為忘記了名稱空間,所以這句會報錯


10.5、uplevel與upvar


10.5.1、名稱空間層級
proc foobar {} { puts "foobar:\t[info level]"; foo; };
proc foo {} { puts "foo:\t[info level]"; bar; };
proc bar {} { puts "bar:\t[info level]" };
puts "global:\t[info level]"
foobar
上面指令碼輸出如下
global: 0
foobar: 1
foo: 2
bar: 3
由此,可以看出最外層空間編號是0,多層函式呼叫時,空間編號依次增長。
10.5.2、uplevel:提升proc層級,去變數所在空間層級,使用外層空間變數
namespace eval foo {
namespace export bar
proc bar {} {
uplevel 1 { set name "Kid"; };#數字1表示相對層級,數字加上井號表示絕對層級
set name "blah...";
}
}
set name "Rex Tsai"
puts $name;輸出Rex Tsai
foo::bar
puts $name;輸出Kid
10.5.3、upvar
upvar - 建立連結到外層空間的變數
用法:upvar ?level? otherVar myVar ?otherVar myVar ...?
level,可選,指空間層級,預設為1,表示連結到外1層空間的變數
otherVar,外層空間的變數名
myVar,連結的名字
令myVar和外層空間的otherVar指向同一個記憶體地址,myVar與otherVar變數值相同,修改myVar等同於修改otherVar
如果外層空間中otherVar不存在,則不會建立myVar.

例一:
upvar:提升proc內的var,連結到外層空間變數,使用外層空間變數
namespace eval foo {
namespace export bar
proc bar {} {
upvar 1 testname j # 或是 upvar #0 testname j
set j "Kid"
}
}
set testname "Rex Tsai"
puts $testname;輸出Rex Tsai
foo::bar
puts $testname;輸出Kid

例二:
set a 1 ;#定義變數a, 並且值設為1

proc test {b} {
upvar $b mya

puts $b

puts $mya

}

test a ;#呼叫函式 test

a ;#引數b的值為a(變數名)

1 ;#由於upvar 使mya(變數名)指向a(變數名)指向的同一個變數,mya的為a的值

upvar使的在函式內部可以更改函式外部的變數的值
10.5.4、uplevel與upvar是通過不同方式使用外層空間變數
upvar 與 uplevel 都必須指定你想使用的名稱空間層級, 如果不指定, 他會使用上一層, 預設值是 1.
另外, 也可以使用抽象的層級號碼, 他的方式是以 #開頭, 後面接一個層級數字
10.5.5、namespace upvar:通過一個變數連結,使用其它空間的變數
namespace upvar ::__script load script_load
load是::__script空間內的變數
可以通過script_load引用load


10.6、刪除名稱空間


namespace delete MyMath


10.7、取得限定名稱的名稱空間部分或者尾部名稱空間


10.7.1、取得頭部的名稱空間部分
% namespace qualifiers China::SiChuan
China
% namespace qualifiers China::SiChuan::Chengdu
China::SiChuan
10.7.2、取得尾部的名稱空間
% namespace tail China::SiChuan
SiChuan
% namespace tail China::SiChuan::Chengdu
Chengdu
10.8、獲取空間名稱
namespace current命令: --> 獲取當前名稱空間的名稱
namespace parent命令: --> 獲取當前名稱空間的父名稱空間
namespace childred命令: --> 獲取當前名稱空間的子名稱空間

11、tcl包、庫、引用檔案


1)在檔案new.tcl中使用source test.tcl命令後,可以在new.tcl中直接使用定義在test.tcl中的過程。

12、檔案IO


tcl內建的處理檔案的命令:open開啟,read讀全部,puts寫,gets讀一行,close關閉檔案。
read例子
set fp [open "input.txt" w]
puts $fp "test"
close $fp
set fp [open "input.txt" r]
set data [read $fp]
puts $data
close $fp
gets例子
set fp [open "input.txt" w]
puts $fp "test1\ntest2"
close $fp
set fp [open "input.txt" r]
while { [gets $fp data] >= 0 } {
puts $data
}
close $fp


13、錯誤處理


catch script ?resultVarName? ?optionsVarName?
如果指令碼產生一個錯誤,catch將返回一個非0的整數,
如果給出了resultVarName變數,當返回1時,儲存在resultVarName中的為錯誤資訊,如果返回0,儲存在resultVarName中的為指令碼執行結果。
1)用catch捕獲自定義error
proc Div { a b } {
if { $b == 0 } {
error "this is error message" "this is error info" 401
} else {
return [expr $a / $b]
}
}
# 注意:被catch的指令碼應該用{}包起來。
if { [catch {Div 10 0} errorMsg]} {
puts "Error Message: $errorMsg"
puts "Error Info: $errorInfo"
puts "Error Code: $errorCode"
}

2)用catch捕獲error


14、tcl內建函式


內建函式列表:https://www.yiibai.com/tcl/tcl_builtin_functions.html
1)數學函式
namespace import ::tcl::mathfunc::*
puts [abs -5];#絕對值
puts [ceil 5.2];#向上取整
puts [floor 5.4];#向下取整
puts [sin [asin 1]];#計算反正弦和正弦值
puts [double 12];#轉為浮點數
puts [fmod 5 2];#5/2的餘數
puts [int 4.5];#取整
puts [pow 4 2];#乘方
puts [rand];#0~1間的隨機數
puts [round 4.6];#四捨五入取整
puts [sqrt 16];#開方
2)時間日期
# 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}]

set date "2020-12-28 18:43:42"
set date [clock scan $date -format {%Y-%m-%d %H:%M:%S}]
puts $date
3)執行系統命令
puts [exec ping 127.0.0.1]
puts [exec ipconfig]


15、正則表示式


1、基本格式
關鍵字 表示式 字串 匹配值 分組1 分組2 ...
regexp {([A-Z,a-z]*).([A-Z,a-z]*)} "Tcl Tutorial" a b c
puts "Full Match: $a";#輸出"Tcl Tutorial"
puts "Sub Match1: $b";#輸出"Tcl"
puts "Sub Match2: $c";#輸出"Tutorial"
2、常用引數
-nocase:忽略大小寫
-line:新行敏感,換行後忽略字元。
-start index:搜獲模式開始設定偏移。
3、常見用法
通常,我們並不關心匹配值,只關心分組,使用->儲存匹配值,格式如下
regexp $exp $string -> sub1 sub2


16、檔案操作


檔案測試
file exists $name ; # 判斷檔案是否**存在**
file isdirectory $name ; # 判斷檔案是否是**目錄**
file isfile $name ; # 判斷檔案是否是**檔案**

file readable $name ; # 判斷檔案是否**可讀**
file writable $name ; # 判斷檔案是否**可寫**
file executable $name ; # 判斷檔案是否**可執行**
file owned $name

檔案路徑、檔名
set name /path/a/b/c.txt

file extension $name ; # .txt
file dirname $name ; # /path/a/b
file rootname $name ; # /path/a/b/c
file tail $name ; # c.txt

file nativename $name ; # 系統預設格式的檔名

檔案資訊
set name /path/a/b/c.txt

file size $name ; # 單位 位元組(bytes)
file stat $name finfo
array get finfo * ; # {atime, ctime, dev, gid, ino, mode, mtime, nlink, size, type, uid}

file separator ; # 系統支援的檔案路徑分隔符

檔案操作
file mkdir $name ; # mkdir -p $name 建立目錄,自動建立父目錄

file copy $source $target ; # copy 檔案: cp $source $target

file delete $path ; # 刪除檔案 rm $path
file delete --force $path ; # 強制刪除非空目錄 rm -rf $path

file rename $source $target ; # mv $source $target

獲取連結(link)的最終目標檔案
在copy操作中,如果遇到 link,而link的目標檔案又是相對路徑的時候,就需要找到link所最終指向的檔案。

proc file_read_link {file} {
while {[file type $file] == "link"} {
set file [file join [file dirname $file] [file readlink $file]]
}
return $file
}
巧妙地利用了 file join 的特性省略了對目標檔案是相對路徑還是全路徑的判斷。

17、格式化format


字元 說明
d 有符號整數
u 無符號整數
i 有符號整數。變元可以是十六進位制(0x)或八進位制(0)格式
o 無符號八進位制數
x 或X 無符號十六進位制數
c 將整數對映到對應的 ASCII 字元
s 字串
f 浮點數
e 或E 科學記數法表示的浮點數
g 或G 以%f 或%e 格式(要短一些)來表示的浮點數
- 使欄位左對齊
+ 欄位右對齊
space 在數字前加一個空格,除非數字帶有前導符號。這在將許多數字排列在一起時非常有用
0 使用 0 作為補白
# 前導 0 表示八進位制,前導 0x 表示十六進位制數。浮點數中總要帶上小數點。不刪除末尾的 0(%g)

例一
#要取第 2 個變元值,即 5。位置說明符的格式為 2$,並用\來引用符號$:
%set res [format "%2\$s" 1 5 9]
=>5
%puts $res
=>5
%set str [format "%3\$s %1\$s %2\$s" "are" "right" "You"]
=> You are right

例二
%format "%x" 20
=>14 ;# 將 20 轉換為十六進位制數
%format "%8x" 20
=> 14 ;# 將 20 轉換為十六進位制數,8 位資料寬度,右對齊
%format "%08x" 20
=>00000014 ;#與上一命令相似,但用 0 添齊
%format "%-8x" 20
=>14 ;#寬度 8 位,左對齊
%format "%#08x" 20
=>0x000014

18、特殊語法


1){*}
功能:將包含多個元素的列表視為多個值,而不是一個值。
舉例:
% set list1 [list 1 2 3]
>>1 2 3
% set list2 [list a b c]
>>a b c
% set concatenation [list {*}$list1 {*}$list2]
>>1 2 3 a b c
% set concatenation [list $list1 $list2]
>>{1 2 3} {a b c}
2)args
功能:當args是最後一個引數時,它是一個列表,由剩餘的全部傳入引數對它賦值。
舉例:
%proc demo {first {second "none"} args} {
puts "first = $first"
puts "second = $second"
puts "args = $args"
}
% demo one two three four five
>>first = one
>>second = two
>>args = three four five
3)subst
功能:通常用於花括號{}內部的反斜線、命令和變數替換
語法:subst ? -nobackslashes? ? -nocommands? ? -novariables? string
描述:這個命令對 string變元執行變數、命令和反斜槓替換,然後返回替換後的結果,替換的方式和執行Tcl命令的方式相同, string變元被替換兩次,一次為Tcl命令的剖析器,另外一次為subst命令。
如果指定了-nobackslashes、-nocommands或-novariables標誌位,那麼相應的替換將不會執行,比如如果指定了-nocommands標誌位,命令替換就不會發生,中括號被當作為普通字元處理。

舉例:
set body {{"oldPsw":"$old_passwd","newPsw":"$new_passwd"}}
set body [subst -nocommands -nobackslashes $body]


19、類與例項(面向物件)


這裡介紹基於TclOO的類與例項。
1)宣告一個類
oo::class create MyExampleClass {
# 關鍵字constructor,類例項化時呼叫這個方法
constructor {args} {# like [proc]
# Do something with the args...
}
# 公共方法用關鍵字method定義,方法名必須是小寫字母開頭
method foo {bar boo} {# like [proc]
puts "bar=$bar, boo=$boo"
}
# 特殊的公共方法
# 當呼叫未定義的方法時,會轉為呼叫unknown方法。
method unknown {args} {
puts "unknown is ok"
}
# 通過關鍵字detroy呼叫destructor方法
destructor {# No arguments
# Clean up here if necessary
}
}
2)類例項化
# 例項化時指定一個名稱
MyExampleClass create exampleObj someArgumentToConstructor...
exampleObj foo 1 2; # prints 'bar=1, boo=2'
exampleObj destroy; # wipes the object out
# 例項化時,賦值給變數
set obj [MyExampleClass new]; # 'Unnamed' object
$obj foo 3 4; # prints 'bar=3, boo=4'
$obj destroy
3)定義例項變數
oo::class create Example2 {
constructor x {
variable X $x
}
method addToX y {
variable X
set X [expr {$X + $y}]
return
}
destructor {
variable X
puts "X is $X"
}
}
Example2 create eg 3
eg addToX 5
eg addToX 2
eg destroy; # Prints 'X is 10'
4)私有方法
# 私有方法名字不以小寫字母開頭。
# 通過關鍵字my呼叫私有方法。
...
method ThePrivateMethod ... ...
method aPublicMethod ... {
puts "before the private call"
my ThePrivateMethod ...
puts "after the private call"
}
...
5)修改類
# 先定義類的名字。
# 再通過oo::define新增類內部的方法。
oo::class create Example2a
# One syntax style: single argument is definition script
oo::define Example2a {
constructor x {
variable X $x
}
destructor {
variable X
puts "X is $X"
}
}
Example2a create foo 3
# Other syntax style: multiple arguments give a single definition
oo::define Example2a method addToX y {
variable X
set X [expr {$X + $y}]
return
}
6)類的繼承
# 定義父類
oo::class create fruit {
method eat {} {
puts "yummy!"
}
}
# 定義子類
oo::class create banana {
# 繼承父類
superclass fruit
constructor {} {
my variable peeled
set peeled 0
}
method peel {} {
my variable peeled
set peeled 1
puts "skin now off"
}
method edible? {} {
my variable peeled
return $peeled
}
# 修改繼承自父類的方法
method eat {} {
if {![my edible?]} {
my peel
}
next
}
}
set b [banana new]
$b eat → prints "skin now off" and "yummy!"
fruit destroy
$b eat → error "unknown command"
7)self
詳見:https://www.tcl-lang.org/man/tcl/TclCmd/self.htm

[self]:返回當前例項的資訊
oo::class create c {
method foo {} {
puts "this is the [self] object"
}
}
c create a
c create b
a foo → prints "this is the ::a object"
b foo → prints "this is the ::b object"
8)next和nextto
詳見:https://www.tcl-lang.org/man/tcl/TclCmd/next.htm
用法1:呼叫類或者父類中的同名方法
oo::class create theSuperclass {
# 父類中的example方法
method example {args} {
puts "in the superclass, args = $args"
}
}
oo::class create theSubclass {
superclass theSuperclass
# 子類中的example方法
method example {args} {
puts "before chaining from subclass, args = $args"
next a {*}$args b
next pureSynthesis
puts "after chaining from subclass"
}
}
theSubclass create obj
# 例項中的example方法
oo::objdefine obj method example args {
puts "per-object method, args = $args"
next x {*}$args y
next
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# 呼叫example方法時,會依次呼叫例項、類、父類中的example方法
obj example 1 2 3
# 列印如下
per-object method, args = 1 2 3
before chaining from subclass, args = x 1 2 3 y
in the superclass, args = a x 1 2 3 y b
in the superclass, args = pureSynthesis
after chaining from subclass
before chaining from subclass, args =
in the superclass, args = a b
in the superclass, args = pureSynthesis
after chaining from subclass

應用一:
[self next]:判斷父類中有無當前方法
nextto和
oo::class create fruit {
method eat {} {
puts "yummy!"
}
method myeat {} {
my eat
}
}
# 定義子類
oo::class create banana {
# 繼承父類
superclass fruit
constructor {} {
my variable peeled
set peeled 0
}
method peel {} {

if {[self next] ne {}} {
puts "has_next"
puts [self next]
} else {
puts "not has"
}

}
# 修改繼承自父類的方法
method eat {} {
if {[self next] ne {}} {
puts "has_next"
puts [self next]
} else {
puts "not has"
}
}
}
set b [banana new]
$b peel;#輸出not has
$b eat;#輸出has_next
9)oo::class
The oo::class class is the class of all classes;every class is an instance of this class, which is consequently an instance of itself.
每一個類都是oo::class的例項。

This class is a subclass of oo::object, so every class is also an object.
oo::class是oo::object的子類,所以每個類都是一個物件。

10)info object isa object用於測試特定單詞是否指向物件,即變數是否存在
% info object isa object abcde
0
% oo::object create abcde
::abcde
% info object isa object abcde
1
% abcde destroy
% info object isa object abcde
0

info object isa category object ?arg?
This tests whether object (a TclOO object) is a member of the given category (possibly as modified by arg). The supported categories are:

info object isa class object
Is object a class? (Being a class means being an instance of oo::class or one of its subclasses.)

info object isa metaclass object
Is object a metaclass? (A metaclass is a subclass of oo::class.)

info object isa mixin object class
Is class directly mixed into object?

info object isa object command
Is command really an object? (If it is, it will be an instance of oo::object or any of its subclasses; that's the whole TclOO class system though.)

info object isa typeof object class
Is object of the type of the given class? (It is if it is an instance of the class or a one of its direct or indirect subclasses.)
11)類物件自己的方法,類似於靜態方法概念
CLASS_DEFINE AUTOGUI {
superclass OBJ
self {
method class_init {} {
}
}
}


20、twapi

1)最小化指定應用的視窗
package require twapi
if {$argc != 1} {
puts stderr "Usage: [info nameofexecutable] $argv0 APPNAME"
puts stderr "Example: [info nameofexecutable] $argv0 notepad"
exit 1
}

set appname [lindex $argv 0]
# Add an extension if none specified
if {[file extension $appname] == ""} {
append appname .*
}

# Get all pids with that app name
set pids [twapi::get_process_ids -glob -name $appname]

# Only minimize if they are marked as visible. This is important
# else hidden windows will be placed on the taskbar as icons
foreach hwin [twapi::find_windows -pids $pids -visible true] {
twapi::minimize_window $hwin
}

2)向指定視窗傳送文字資訊
package require twapi
if {$argc != 2} {
puts stderr "Usage: [info nameofexecutable] $argv0 WINDOWTITLE TEXT"
exit 1
}

set title [lindex $argv 0]
set data [lindex $argv 1]
# Get all windows with that title
set windows [twapi::find_windows -text $title]
if {[llength $windows]} {
set win [lindex $windows 0]
# Set the focus to the window
twapi::set_focus $win
# Feed data into the input queue
twapi::send_input_text $data
} else {
puts stderr "No windows found with title '$title'"
}

20、socket

20.1、socket 服務端開啟
格式:socket –server command ?options? port
-server :表明開啟的是伺服器端
port:埠
command:當有客戶端來連線的時候,執行這個過程,這個過程有三個引數
channel:給新客戶端的通道
address:提供給客戶端連線的 ip 地址
port:埠

20.2、客戶端連線伺服器端
格式:socket ?options? host port
host port :客戶端連線的伺服器 ip和埠

20.3、fileevent定義了一個控制代碼,滿足條件時執行
格式:fileevent channelId readable? script?
fileevent channelId writeable? script?
readable:當通道 channelId 有資料準備好被讀了,執行指令碼 script
writeable:當通道 channelId 有資料準備好接收資料了,執行指令碼 script

20.4、vwait 命令使執行暫停,直到 varName 被賦值,即便賦值前後相同
格式:vwait varName


例子一:簡單的客戶端連線服務端
-----------------------------------------------------------------------------------------
server:
proc accept {chan addr port} {
puts "$addr:$port says [gets $chan]"
puts $chan goodbye;#向通道傳送goodbye
close $chan
}
socket -server accept 12345
vwait forever

client:
set chan [socket 127.0.0.1 12345]
puts $chan hello;#向通道傳送hello
flush $chan
puts "server says [gets $chan]"
close $chan

執行結果:
-servr
127.0.0.1:3148 says hello
-client
server says goodbye

例子二:顯示服務端時間
格式:clock seconds
功能:返回從計算機紀元開始的秒數,不同作業系統開始時間可能不同,所以這個值通常用來作為命
令 clock format 的輸入
clock format [clock seconds] 返回當前時間
clock format [clock seconds] -format %H:%M:%S 以“時:分:秒”形式返回當前時間
-----------------------------------------------------------------------------------------
server:
proc Server {channel clientaddr clientport} {
puts "Connetion from $clientaddr $clientport registered"
puts $channel [clock format [clock seconds]]
close $channel
}
socket -server Server 9911
vwait forever

client:
set chan [socket 127.0.0.1 9911]
gets $chan line;#讀取通道中的資訊
close $chan
puts "The time on $chan is $line"

執行結果:
-server
Connetion from 127.0.0.1 3163 registered
-client
The time on sock268 is Tue Dec 15 09:07:00 +0800 2009

20、子程序呼叫--open&exec
1.格式:open |progName ?access?

功能:為管道返回一個檔案描述符。如果proName用括號括起來,可以包含引數。

2.格式:exec ?switches? arg1? arg2?...?argN?

功能:執行子程序。

*switches :-keepnewline 管道輸出的每行後面加個新行。

--:標誌開關結束,哪怕後面跟著有-開頭的字串,都作為引數處理

*argN 引數可以是可執行程式;作為子程式執行的命令列;輸出重定向。

輸出重定向包括:
序號 重定向 描述
1 | 將標準輸出重定向到標準輸入中
2 <fileName 管道中的第一個程式將讀入檔案內容
3 <@fileID 管道中第一個程式將讀入檔案描述符中的內容,該檔案描述符是使用open.."r" 的返回
4 <<value 管道中第一個程式讀到這個值
5 >fileName 管道中最後一個程式的輸出內容覆蓋寫入檔案
6 >>filename 管道中最後一個程式的輸出內容寫入檔案,新增到檔案的末尾。
7 2>filename 管道中所有程式的標準錯誤輸出到檔案,覆蓋檔案原有內容
8 2>>filename 管道中所有程式的標準錯誤輸出到檔案,新增到檔案末尾
9 >@file 管道中程式輸出內容寫到檔案描述符,該檔案描述符是用open .. W開啟

程式碼示例如下:
set io [open "|C:/Windows/system/teacup.exe" r+];#open呼叫外部程式
set invert [exec C:/Windows/system/teacup.exe];#exec呼叫外部程式

因為管道的例子在 windows 下比較難舉,現以 unix 下一段程式碼為例子,通過管道讀出 ps(列出程序)

命令的輸出:
tclfolder%tclsh
% set fid [open "|ps -ef" r+]
file5
% gets $fid line;puts "line: $line"
line: UID PID PPID C STIME TTY TIME CMD
% gets $fid line;puts "line: $line"
line: root 1 0 0 Nov 11 - 0:01 /etc/init
% gets $fid line;puts "line: $line"
line: root 86118 1 0 Nov 11 - 5:00 /usr/sbin/syncd 60
% gets $fid line;puts "line: $line"
line: tclll 90248 893094 0 11:54:55 pts/14 0:00 -csh
% gets $fid line;puts "line: $line"
line: root 110730 1 0 Nov 11 - 0:00 /usr/sbin/uprintfd
% gets $fid line;puts "line: $line"
line: root 118848 1 0 Nov 11 - 0:00 /usr/ccs/bin/shlap64
% exit
tclfolder%


注意事項:
1、
set a "hello"
puts "$a"
但不能寫成
puts {$a}
這樣的話$a不會做變數替換。
基本的替換規則:""號中的變數、命令、\替換;{}中的內容不替換。
這裡的""和{}都是最外層的,如果是在裡面,不影響外層是否替換的規則。

2、給引數傳空值:用引號
proc cal {{a 1} {b 2} {c 3}} {
puts "!$a!$b!$c!"
}
cal 1 "" 3;#輸出!1!!3!

3、給引數傳"[{"a":1,"b":2},{"a":2,"b":4}]"形式的資料,方括號需要進行轉義或者用{}
set data '\[{"a":1,"b":2},{"a":2,"b":4}\]'
puts $data

4、多加空格引起報錯
set data '\[{"a":1,"b":2},{"a":2,"b":4} \]';#右花括號和斜槓之間有一個空格,會引起報錯
puts $data
報錯提示如下
wrong # args: should be "set varName ?newValue?"

5、單引號與雙引號的區別是?