TCL是一种类似shell脚本的语言,你可以使用它来完成许多操作。不过,我介绍它的
主要原因是expect是从它发展出来的。如果你想要写一个能够自动处理输入输出的脚本 (如向用户提问并且验证密码)又不想面对C或者Perl,那么expect是你的唯一选择。
11.1.1 TCL语言 要使用TCL,你必须先安装这个程序: % rpm -q tcl tcl-8.0.5-30 TCL语言可以用交互式或者脚本的方式执行,要使用交互式的TCL环境,只要输入 $ tclsh % 出现的"%"符号是TCL的提示符,然后就可以使用TCL命令的。 如果你要使用脚本方式的TCL,首先把你的脚本写成一个文本文件,例如test.tcl,然 $ tclsh test.tcl 在tcl脚本中,每一行或者是一个命令行,或者是一个注释。注释行必须以#符号开头 变量 在tcl中,有两种基本类型的变量,即标量和数组。标量就是一般的数字或者字符串变 % set i 1 1 字符串应该用引号括起来: % set str "test" 'test' 要输出一个标量的内容,使用put语句: % puts $str test $用来说明str是一个变量。puts函数在标准输出显示变量的内容。 数组也可以用set语句定义,实际上,tcl中建立数组只是单个建立数组的元素。例如 % set arr(1) 0 0 % set arr(2) 1 1 这样就建立了一个两个元素的数组arr。在TCL中,不存在相当于数组边界这样的东西 % set arr(100) to to 这时数组中实际只存在arr(1),arr(2)和arr(100),这是和C语言不同的地方。用arr % array size arr 3 访问数组的方法和访问标两实际是一样的,例如: % puts $arr(100) to 可以用同样的方法创建多维数组。 要使用数组中的所有元素,需要使用一种特殊的便利方式。首先要启动startsearsh: % array startsearch arr s-1-arr 这里返回了一个搜索id,你可以把它传递给某个变量,因为以后还要使用它进行进一 % set my_id [array startsearch arr] s-1-arr 现在my_id的内容是s-1-arr,然后,就可以搜索arr的内容了: % array nextelement arr $my_id whi 这里的array nextelement返回的是什么?可能有点出乎你的意料,是arr数组的下标 % array nextelement arr $my_id 4 这样遍历下去,可以找出arr数组的所有下标,而知道下标之后,就可以用$arr(4)之 % array nextelement arr $my_id % 这时就可以停止遍历过程了,如果你想确认遍历是否完成,可以使用array anymore命 % array anymore arr $my_id 0 返回0说明遍历已经完成。 串处理 TCL中可以进行一般的串处理过程,这可以使用string命令和append命令,append命令 % set str1 "test " test % set str2 "cook it" cook it % append str1 $str2 " and other" test cook it and other string命令可以执行字符串的比较,删除和查询,其格式是 string [参数] string1 参数可以是下面的命令之一: compare 按照字典顺序对字符串进行比较,根据相对关系返回-1,0或者+1。 first 返回string2中第一次出现string1的位置,如果失败,返回-1。 last 返回string2中最后一次出现string1的位置,如果失败,返回-1 trim 从string1中删除开头和结尾的出现在string2中的字符 trimleft 从string1中删除开头的出现在string2中的字符。 trimright 从string1中删除结尾的出现在string2中的字符 下面几个用在string中的参数不需要string2变量: length 返回tring1的长度 tolower 返回将string1全部小写化的串 toupper 返回将string1全部大写化的串 运算 TCL的运算方式比较别扭,它使用expr命令作为计算符号,其用法类似C语言的+=和/= % set j [expr $i/5] 1 注意TCL会自动选择整数或者浮点计算: % set l [ expr $i /4.0] 1.25 % set l [ expr $i /4] 1 在TCL里面可以使用+ - * /和%作为基本运算符,另外通常还包括一些数学函数,如a 另外,还有一个起运算符作用的命令incr,它用来对变量加一: % set i 1 1 % incr i 2 流程控制 tcl支持分支和循环。分支语句可以使用if和switch实现。if语句的和C语言类似,如 if { $ x < 0 } { set y 10; } 注意判断子句也需要使用花括号。 与C语言一样,tcl的if语句也可以使用else和elseif。 switch语句的用法有点类似这样: switch $x { 0 { set y 10;} 10 { set y 100;} 20 { set y 400;} } 与C的switch语句不同,每次只有符合分支值的子句才被执行。 循环命令主要由for,foreach和while构成,而且每一个都可以使用break和continue for语句的格式有点类似这样: for { set i 0} {$i < 10} { incr i} {puts $i} 将会输出从1到9的整数。 如果用while循环,这个句子可以写成 while {$i < 10 } { puts $i; incr i; } foreach是对于集合中的每一个元素执行一次命令,大致的命令格式是 foreach [变量] { 集合 } { 语句; } 例如 % foreach j { 1 3 5} { put $j; } 1 3 5 函数 如同在一般的编程语言里面一样,在tcl里面也可以定义函数,这是通过proc命令实现 proc my_proc {i}{ puts $i; } 这样就定义了一个名字叫proc的函数,它只是在终端显示输入变元的内容。 要使用这个函数,简单地输入它的名字: % my_proc { 5 } 5 如果变元的数目是0,只要使用空的变元列表,例如 proc my_proc {} {语句;} 尽管tcl还可以处理更复杂的过程,但是我们不再介绍了,例如文件的读写以及tk图形 11.1.2 expect expect是建立在tcl基础上的一个工具,它用来让一些需要交互的任务自动化地完成。 我们看一看这样的一个例子脚本: #! /usr/bin/expect spawn ftp 202.199.248.11 expect "Name" send "ftp/r" expect "Password:" send "nothing/r" expect "apply" send "cd /pub/UNIX/Linux/remoteX/r" expect "successful." send "bin/r" expect "set to I" send "get exceed5.zip/r" expect "complete." send "quit/r" 这个是什么意思?呵呵,就是个自动下载程序。第一行说明这个程序应该调用/usr/b 察看expect的手册页面(man expect)可以得到一个很长的expect说明,可惜其中关于 spawn语句在expect脚本中用于启动一个新的进程,在我们的程序中,spawn ftp 202 每一对expect和send指令代表一个信息/回应。如果这样说不好理解的话,那么可以看 ftp 202.199.248.11 Connected to 202.199.248.11. 220 mail.asnc.edu.cn FTP server (BeroFTPD 1.3.3(3) Sun Feb 20 15:52:49 CST Name (202.199.248.11:wanghy): 显然,一旦连接成功,服务器会返回一个Name(202.199.248.11:wanghy):的字符串来 send命令比expect命令更简单,它简单地向标准输入提交你设定的字符串,现在设置 下面的行与这些行完全一样,只是机械地等待服务器的回应,并且提交自己的输入。 要使用这个expect脚本,你只需要将它设置为可执行的属性,然后执行它,expect就 由于expect是tcl的扩展,所以你在expect文件中可以象tcl脚本一样设置变量和程序 现在我们看一看我们还能够如何改进我们的expect脚本。ftp命令可能会失败,比如远 #! /usr/bin/expect spawn ftp 202.199.248.11 expect { timeout exit Connect } ……………… 注意这里面使用的花括号。它的含义是使用一组并列表达式。使用并列表达式的主要 expect timeout exit 那么由于expect脚本是顺序执行的,那么当程序执行到这个expect的时候就会阻塞, 我们可以看看用tcl能够对我们的expect脚本提供什么帮助。我们可以设置让expect脚 spawn ftp while {1} { expect "ftp>" send "o 202.199.248.11/r" expect { "Connected" break "refused" { sleep 10} ; } } 这里使用了我们在tcl语言中讲到的while和break命令,熟悉C的读者应该很容易看出 expect还支持许多更复杂的进程控制方式,如fork,disconnect等等,你可以从手册 有些读者可能会问,如果expect执行的话是否控制台输入不能使用了,答案是否定的 缺省下,expect在标准输出(你的终端上)输出所有来自应用程序的回应信息,你可 log_file [文件名] 这个命令让expect在你设置的文件中记录输出信息。必须注意,这个选项并不影响控 log_file expect.log log_user 0/1 这个选项设置是否显示输出信息,设置为1时是缺省值,为0 的话,expect将不产生任 这一点很让人困扰,如果你确实想要记录expect的输出却不想让它在控制台上制造垃 ./test.exp > /dev/null 你可以象下面这样使用一对fork和disconnect命令。expect的disconnect命令将使得 if [fork]!=0 exit disconnect fork命令会产生出一个子进程,而且它产生返回值,如果返回的是0,说明这是一个子进程,如果不为0,那么是父进程。因此,执行了fork命令之后,父进程死亡而子进程被disconnect命令放到后台执行。注意disconnect命令只能对子进程使用。 |
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。