关键词:TCL、配置文件、unix 一.应用范围在实际工作中,TCL脚本对于一些简单的工作裨益甚大。通常编写脚本都有一定的模式,首先从配置文件读入配置项,初始化变量,然后进行处理,最后输出,在程序的运行过程中需要把一些信息写入日志文件,而调试信息写入日志文件和直接输出到屏幕都可以。 使用任何一种脚本,通常也都会根据实际情况建立起自己的函数库,而这个函数库中对配置文件配置项的读取无疑是非常基本而重要的。 这篇文章的本意是引导刚接触TCL脚本的朋友尽快上手,所以有些细节的说明文字比较细。 二.程序讲解构建一个配置文件,尽可能的接近实际应用: 文件名:config.ini 文件内容: # #这是注释行 # [] key1=value1 #注释 [section1] key2=value2 [section2] key1=value2 [section1] key1=xxxxxx #这是最后的返回 [section1] key1=value2 现在开始对程序的说明: ;#------------------------------------------------------------------------- ;#功能:从配置文件中读取配置项 ;#输入:1. configFile:配置文件名称 ;# 2. Section :段名称 ;# 3. Key :关键字 ;# 4. Comment :注释符,缺省为井号 ;# 5. Equal :关键字和值的分隔符,缺省为等号 ;#输出:1. Value :相应的值 ;#------------------------------------------------------------------------- 1.过程的定义: 格式:proc name args body 要点: Ø 参数列表使用花括号引起; Ø 变量没有类型; Ø 变量之间使用空格间隔; Ø 如果参数有缺省值,使用花括号引起,并赋值 proc getConfig { configFile Section Key {Comment "#"} {Equal "="}} { set Value "" ;#记录过程返回的值 set FindSection 0 ;#记录是否找到了section 2.错误的处理 格式:catch script ?varName? 功能:执行script,如果成功返回TCL_OK(0),否则返回TCL_ERROR(1),提示结果存在varName中。比如下面如果打开文件成功,errMsg返回的就是类似file3这样的字符串,此时err返回的是TCL_OK,就是零;如果文件不存在,errMsg返回的类似:couldn't open "config1.ini": no such file or directory,此时err返回TCL_ERROR,就是一。 3.文件的读写 格式:openfile fileName ? access ? permission 讲解: Ø fileName是文件名称; Ø access是存取模式,可以为r, r+, w, w+, a, a+六种模式,r、r+和a三种模式文件必须已经存在,其他三种模式文件不存在就创建一个。本文用的r模式,所以文件不存在会提示错误,而不是自动建立一个; Ø permission是权限,举例说明: Ø 文件打开后就可以使用其文件id,使用完后记得关闭文件 ;#打开配置文件 set err [catch {set fileid [open $configFile r]} errMsg] if {$err == 1} { puts "errMsg : $errMsg" return $Value } ;#成功打开文件后,一行一行的加以分析 set rowid 0 ;#记录当前行数,程序调试时打印调试信息使用的 seek $fileid 0 start ;#定位到文件头 while {[eof $fileid] != 1} { ;#读取文件内容 4.变量的自动增长使用命令incr,也可以使用set rowid [expr $rowid + 1],显然前者更简捷 incr rowid ;#记录行数,从一开始
;#读出一行 gets $fileid line
5.先期处理行,因为注释有两种情况,行中的注释和整行注释,先去掉注释,然后去左右空格就可以得到真正需要的内容;如果先去空格,再去注释,由于行中的注释和内容之间有空格,这样最后得到的内容在去掉行中注释后,会在后面留下一些空格。所以需要先去掉注释,后去掉空格。 6.得到一个字符串在另一个字符串中首先出现的位置,使用函数string first 格式:string first string1 string2 讲解:返回string1在string2中第一次出现的位置;如果string1不在string2中,返回-1 7.下面有一个细节是初学者经常犯错的地方,那就是:} else {,这里必须严格的花括号,空格,else,空格,花括号,不能把花括号写到上一行或者下一行。 8.返回一个字符串的子串使用string range函数 格式:string range string1 frompos topos 讲解:取string1的从frompos到topos之间的字符串,注意这里字符串下标是从零开始的,所以用string length string1得到的字符串的长度比字符串最后一个字符的位置值要大一。如果取一个字符串中的某个字符就可以使用函数string index string1 pos。 9.expr和unix shell中一样,是进行数学运算的函数。 ;#先去掉注释,再去掉两端的空格 set commentpos [string first $Comment $line] ;#得到注释符号的位置 if { $commentpos == 0 } { ;#行以注释符号开头,忽略掉该行 } else { if { $commentpos != -1 } { ;#行中有注释符号,去掉注释 set line [string range $line 0 [expr $commentpos-1]] }
set line [string trim $line] ;#去掉两端的空格 ;# puts "$rowid : line : $line"
10.在tcl脚本中,循环中有break命令跳出循环,continue跳到循环的开头。不过因为括号的使用,其实这里写不写continue都没有问题。 ;#如果是空就继续循环 if { $line == "" } { ;#回循环 continue } else { ;#先找section set linelen [string length $line] ;#字符串长度 set lastpos [expr $linelen - 1 ] ;#字符串最后的位置 ;# puts "$rowid :len: $linelen lastpos: $lastpos" if { [string index $line 0] == "\[" && [string index $line $lastpos] == "\]" } { ;#如果是查找的section,修改标志位;如果不是相应的section,需要将标志重新赋值 if { [string range $line 1 [expr $lastpos - 1 ]] == $Section } { ;# puts "$rowid: find section : $Section" set FindSection 1 } else { set FindSection 0 } } else { ;#已经找到了section才继续找key if { $FindSection == 1 } { set equalpos [string first $Equal $line] ;#得到等号的位置 if { $equalpos != -1} { ;#如果就是找寻的key,结束循环 if { [string range $line 0 [expr $equalpos - 1]] == $Key } { puts "$rowid: find key" set Value [string range $line [expr $equalpos + 1] [string length $line]] puts "$rowid: find value: $Value" break } } else { ;#回循环 } } else { ;#回循环 } } } } } ;#关闭文件 close $fileid
return $Value } set val "" ;#测试正常情况下 set val [getConfig "config.ini" "section1" "key1"] puts "val : $val" ;#测试文件不存在的情况下 set val [getConfig "config1.ini" "section1" "key1"] puts "val : $val" 该程序在unix环境下调试通过。 三.伪代码为了便于理解程序,特写了下面的伪代码: 打开配置文件 IF出错THEN 过程结束 END IF 文件打开成功,定位到文件头 WHILE没有到文件尾 读出一行
热门推荐博文推荐热点聚焦 |