`
universsky
  • 浏览: 92899 次
文章分类
社区版块
存档分类
最新评论

脚本语言TCl教程:6

 
阅读更多

source

1. source的用途

Ø 将一个程序分为多个文件;

Ø 可以将一组过程放到一个文件中,成为一个库文件;

Ø 配置程序;

Ø 加载数据文件。

2. 格式:source fileName

说明:

Ø 读入文件并执行;

Ø 如果代码出错,source返回那个错误

Ø 如果执行到返回,就立刻返回,即便返回命令后面还有命令也不执行立刻返回

Ø 如果文件名以 ~ 开头,替换为环境变量 $HOME

例子:031_source.tcl

set filename "C:\\windows\\temp\\TT_[pid]"

set outfile [open "$filename" "w"];

puts $outfile {set scr [info script]}

puts $outfile "proc testproc {} {"

puts $outfile "global scr;"

puts $outfile "puts \"testproc source file: \$scr.\""

puts $outfile "puts \"testproc executing from \[info script]\n\""

puts $outfile "}"

puts $outfile {set abc 1};

puts $outfile {return};

puts $outfile {set aaaa 1} ;#没有执行这一句

close $outfile;

puts "This is the contents of $filename:"

puts ".............................................................."

puts "[exec cmd /C type $filename]"

puts ".............................................................."

puts "\n"

puts "Global variables visible before sourceing $filename:"

puts "[lsort [info globals]]\n"

if {[info procs testproc] == ""} {

puts "testproc does not exist. sourceing $filename"

source $filename ;#加载上过程后,就可以调用了

}

puts "\nNow executing testproc"

testproc ;#执行过程

puts "Global variables visible after sourceing $filename:"

puts "[lsort [info globals]]\n"

exec cmd /c del $filename ;#删除该文件

1.2 :建库-unknown & info library

1. 自动加载库文件的方法:

2. 建库的相关函数列表

序号

函数

描述

1

auto_mkindex libdir file1...filen

为库文件创建索引文件(tclIndex),自动加载库的过程定义在init.tcl 文件中,当tclsh启动的时候执行

2

info library

返回库所在路径,实际是环境变量TCL_LIBRARY的值,tcl会在该路径下查找init.tcl

3

unknown args

当解释器遇到调用索引文件中不存在的过程是,该函数尝试下面的步骤来执行命令:

1. 查找auto_path的路径中的索引文件,如果找到过程定义,使用auto_load过程加载执行;

2. 如果解释器交互执行的,tcl尝试使用过程auto_exec去执行;

3. 如果命令是个不带后缀名的tcl命令,unknown完善命令名字,并执行

例子:032_source.tcl

;# Set up a temporary file with a test proc.

set filename "C:/temp/TT_[pid]" ;#1. 生成文件

set outfile [open "$filename" "w"];

puts $outfile {set scr [info script]}

puts $outfile "proc testproc {} {"

puts $outfile "global scr;"

puts $outfile "puts \"testproc source file: \$scr.\""

puts $outfile "puts \"testproc executing from \[info script]\n\"" ;#注意:返回的是032_source.tcl 而不是TT_[pid]

puts $outfile "}"

close $outfile;

puts "The directories in the auto path are: $auto_path\n"

puts "The default library is: [info library]\n";

auto_mkindex "C:/temp" [file tail $filename] ;#2. 对文件建立索引文件,c:/temp 路径下生成索引文件 tclIndex

# With Tcl8.3, this must come after auto_mkindex.

lappend auto_path "C:/temp" ;#3. 将库的路径加到 auto_path

if { [info procs testproc] == ""} {

puts "testproc does not exist\n"

}

testproc

if { [info procs testproc] != ""} {

puts "\ntestproc does exist now"

}

file delete C:/temp/tclIndex

file delete $filename

1.3 :创建命令-eval

1.在程序运行的过程中,tcl可以执行其中创建的命令

格式:eval arg1 ??arg2??... ??argn??

功能:将参数连接成一个字符串,传递给tcl_Eval 进行执行,并返回结果或错误码

例子:033_eval.tcl

set cmd {puts "Evaluating a puts"}

puts "CMD IS: $cmd"

eval $cmd

if {[string match [info procs tempFileName] ""] } {

puts "\nDefining tempFileName for this invocation"

set num 0;

set cmd "proc tempFileName "

set cmd [concat $cmd "{} {\n"]

set cmd [concat $cmd "global num;\n"]

set cmd [concat $cmd "incr num;\n"]

set cmd [concat $cmd " return \"/tmp/TMP.[pid].\$num\";\n"]

set cmd [concat $cmd "}"]

eval $cmd

}

puts "\nThe body of tempFileName is: \n[info body tempFileName]\n"

puts "tmpFileName returns: [tempFileName]" ;# 这里$num返回1

puts "tmpFileName returns: [tempFileName]" ;# $num加一,返回2

1.4 :在eval中应用format & list

1.常见的eval错误

okeval puts ok

erreval puts not ok

okset x “OK” ; eval puts $x

errset x “NOT OK”; eval puts $x

not ok被解析为了两个参数

下面三种写法是正确的:

eval [list puts {NOT OK}]

eval [list puts “NOT OK”]

set cmd “puts”; lappend cmd {NOT OK};eval $cmd

结论:对于构建eval的需要的命令,要么使用stringformat,要么使用listlappend

2.格式:info complete string

功能:检查字符串中的空格,引号,括号等是否匹配,匹配返回一,不匹配返回零

例子:034_format_list.tcl

set cmd "OK"

eval puts $cmd ;#正确

set cmd "puts" ; lappend cmd {Also OK}; eval $cmd ;#正确

set cmd "NOT OK"

#eval puts $cmd ;#出错

eval [format {%s "%s"} puts "Even This Works"] ;#正确

set cmd "And even this can be made to work"

eval [format {%s "%s"} puts $cmd ] ;#正确

set tmpFileNum 0;

set cmd {proc tempFileName }

lappend cmd ""

lappend cmd "global num; incr num; return \"/tmp/TMP.[pid].\$tmpFileNum\"" ;#这里$tmpFileNum不会返回0,会返回$tmpFileNum,因为它是在过程外赋值的

eval $cmd

puts "\nThis is the body of the proc definition:"

puts "[info body tempFileName]\n"

set cmd {puts "This is Cool!"}

if {[info complete $cmd]} {

eval $cmd

} else {

puts "INCOMPLETE COMMAND: $cmd"

}

1.5 :不使用eval替换-format & subst

1.不使用eval的时候,字符串会进行一次置换

例如: set a “sampleA”

set c a

puts “$$c” ;#会返回$a,而不是$a的值

要想进行多次置换,需要使用format或者subst,使用一次置换一次

注意:使用双引号会置换一次,但是使用花括号不会置换

2.格式:subst ?-nobackslashes??-nocommands??-novariables? string

-no后面接什么就不置换什么

例子:

set a "alpha"

set b a

puts {a and b with no substitution: $a $$b}

puts "a and b with one pass of substitution: $a $$b"

puts "a and b with subst in braces: [subst {$a $$b}]"

puts "a and b with subst in quotes: [subst "$a $$b"]\n"

puts "format with no subst [format {$%s} $b]"

puts "format with subst: [subst [format {$%s} $b]]"

eval "puts \"eval after format: [format {$%s} $b]\""

set num 0;

set cmd "proc tempFileName {} "

set cmd [format "%s {global num; incr num;" $cmd]

set cmd [format {%s return "/tmp/TMP.%s.$num"} $cmd [pid] ]

set cmd [format "%s }" $cmd ]

eval $cmd

puts "[info body tempFileName]"

set a arrayname

set b index

set c newvalue

eval [format "set %s(%s) %s" $a $b $c]

puts "Index: $b of $a was set to: $arrayname(index)"

set x "xyz"

set y x

set z y

puts "xyz is : $x $$y $$$z"

puts "xyz is : [subst "$x $$y $$$z"]" ;#返回:xyz xyz $x

puts "xyz is : [subst [subst "$x $$y $$$z"]]" ;#返回:xyz xyz xyz

1.6 :改变工作目录- cd & pwd

1. 改变工作目录

格式:cd ?dirName?

功能:改变当前目录到dirName,如果没有dirName就改变到当前用户的工作目录$HOME,或者目录是 ~ ,也是改变到当前用户的工作目录$HOME,如果是 ~ 开头,后面紧跟的字符被解析为loginid

2. 显示当前路径:pwd

例子:036_cd_pwd.tcl

set dirs [list C:/windows C:/windows/system C:/temp C:/foo ]

puts "[format "%-15s %-20s " "FILE" "DIRECTORY"]"

foreach dir $dirs {

catch {cd $dir}

set c_files [glob -nocomplain c*]

foreach name $c_files {

puts "[format "%-15s %-20s " $name [pwd]]"

}

}

1.7 :调试和错误-errorinfo & errorCode & catch

1.错误相关:

序号

命令或变量

描述

1

error message ?info? ?code?

生成一个错误条件,如果info或者code有值,变量errorInfoerrorCode就这两个值被初始化

2

catch script ?varName?

执行script,如果成功返回TCL_OK,否则返回TCL_ERROR,结果存在varName中。书上这么说的,但是我的试验结果是失败varName存储的错误信息,成功varName存储的0

3

return ?-code code? ?-errorinfo info??-errorcode errorcode??value?

生成一个返回异常条件

-code :返回状态,可以是:

okerror,无,break

-errorinfoinfoerrorInfo变量中的第一个字符串

-errorcode:过程设置errorcode为全局变量的errorCode

value:过程返回值

4

errorInfo

包含了命令错误信息的全局变量

5

errorCode

包含了命令错误代码的全局变量

例子:037_error.tcl

proc errorproc {x} {

if {$x > 0} {

error "Error generated by error" "Info String for error" $x

}

}

catch errorproc

puts "after bad proc call: ErrorCode: $errorCode" ;#这里errorCode返回NONE

puts "ERRORINFO:\n$errorInfo\n"

set errorInfo "";

catch {errorproc 0}

puts "after proc call with no error: ErrorCode: $errorCode" ;#这里errorCode返回NONE,没有错误提示信息

puts "ERRORINFO:\n$errorInfo\n"

catch {errorproc 2}

puts "after error generated in proc: ErrorCode: $errorCode" ;#这里errorCode返回2

puts "ERRORINFO:\n$errorInfo\n"

proc returnErr { x } {

return -code error -errorinfo "Return Generates This" -errorcode "-999"

}

catch {returnErr 2}

puts "after proc that uses return to generate an error: ErrorCode: $errorCode" ;#这里errorCode返回999

1.8 puts "ERRORINFO:\n$errorInfo\n" ;#这里返回的错误信息:调试-trace

1.调试方法:

序号

命令

描述

1

trace variable variableName operation procname

跟踪变量variableName

operation 可以是:

rread ,读

wwrite ,写

uunset ,取消

当变量有相应操作执行procname

2

trace vdelete variableName operation procname

取消变量variableName相应操作operation的跟踪

3

trace vinfo variableName

返回跟踪的变量variableName的信息

例子:

proc traceproc {variableName arrayElement operation} {

set op(w) "Write"; set op(u) "Unset"; set op(r) "Read" ;#定义一个操作数组

set level [info level]

incr level -1;

if {$level > 0} {

set procid [info level $level]

} else {set procid "main"} ;#当级别为零,设置为main,在主程序中

if {![string match $arrayElement ""]} { ;#判断跟踪的变量是否是数组

puts "TRACE: $op($operation) $variableName($arrayElement) in $procid"

} else {

puts "TRACE: $op($operation) $variableName in $procid"

}

}

proc testProc {input1 input2} {

upvar $input1 i

upvar $input2 j

set i 2

set k $j;

}

1.9 trace variable i1 w traceproc ;#传递给traceproc的三个参数分别是:i1,空,w,当i1是数组的时候,:命令行参数和环境串

1.程序和用户交互的方法有很多,以下是其中四种:

Ø 提示用户输入需要信息;

Ø 读入配置文件;

Ø 从命令行读入参数;

Ø 从环境变量读入

2.命令行参数:argc得到参数个数,argv0得到程序自身名字,argv得到其他参数,注意没有argv1这类的全局变量

3env是存储着环境变量的数组,对环境变量修改只是当前程序中生效了

例子:039_arg.tcl

puts "There are $argc arguments to this script"

puts "The name of this script is $argv0" ;#得到程序名

if {$argc > 0} {puts "The other arguments are: $argv" } ;#得到其他的参数

puts "You have these environment variables set:"

foreach index [array names env] {

puts "$index: $env($index)"

}

set prompt "\$P"

if { [info exists env(PROMPT)] } {

puts "$env(PROMPT)" ;#返回 $P$G

set env(PROMPT) $prompt ;#设置环境变量为$P,程序执行完后仍然是$P$G,因为它只是在该程序中生效了

puts "$env(PROMPT)"

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics