Expect 学习笔记

  • 格式:doc
  • 大小:136.00 KB
  • 文档页数:23

Expect学习笔记————Tim一、Expect介绍Expect是一种TCL扩展性的语言,主要用于完成系统交互方面的功能,比如SSH、FTP等,这些程序都需要手工与它们进行互动,而使用Expect就可以模拟人手工互动的过程,使用一种自动的方式控制。

Expect中,有三个重要的主命令,分别是spawn、expect、exp_send,这三个命令几乎存在于所有Expect脚本中,除了这些之外,还有很多Expect所特有的参数、变量,它们也作用与Expect的方方面面。

二、Expect命令Expect中命令是最重要的部分,它们完成Expect中最关键的功能,命令使用的特点就是他们本身就可以单独执行,使用上类似于:命令 [选项] 参数spawnspawn命令是Expect的初始命令,它用于启动一个进程,之后所有expect操作都在这个进程中进行,如果没有spawn语句,整个expect就无法再进行下去了,使用方法就像下面这样:spawn ssh root@192.168.0.1在spawn命令后面,直接加上要启动的进程等信息当然,如果真的不要spawn过程也没有关系,虽然这样就没有办法单独执行,但是这个脚本可以与任何调用它的进程进行交互。

除此之外,spawn还支持其他选项:-open 启动文件进程,具体说明请参照下面的选项部分。

-ignore 忽略某些信号,具体说明请参照下面的选项部分。

expect使用方法:expect 表达式动作表达式动作………………expect命令用于等候一个相匹配的输出,一旦匹配就执行后面的动作,这个命令接受几个特有参数,用的最多的就是-re,表示使用正则表达式的方式匹配,使用起来就像这样:spawn ssh root@192.168.0.1expect ―password:‖ {exp_send ―word\r‖}从上面的例子可以看出,expect是依附与spawn命令的,当执行ssh命令后,expect就匹配命令执行后的关键字:password:,如果匹配到关键字就会执行后面包含在{}括号中的exp_send动作,匹配以及动作可以放在二行,这样就不需要使用{}括号了,就像下面这样,实际完成的功能与上面是一样的:spawn ssh root@192.168.0.1expect ―password:‖exp_send ―word\r‖expect命令还有一种用法,它可以在一个expect匹配中同时匹配多个关键字,只需要将关键字放在一个大括号中就可以了:spawn ssh root@192.168.0.1expect {-re ―password:‖ {exp_send ―word\r‖}-re ―TopsecOS#‖ { }}上面的例子中,在一个expect匹配中可以匹配二个不同情况,如果发现有password:字符就执行后面的动作,而发现的是另外一个TopsecOS#时,因为后面的动作为空,就会退出这个expect动作,在这些动作中也有很多参数,我们在后面来慢慢介绍。

上面我们看到了一种【表达式-动作】模式,还有人喜欢使用另一种格式,就像下面这样:spawn ssh root@192.168.0.1expect –re ―password:‖ {exp_send ―word\r‖} –re ―TopsecOS#‖ {}这种格式的好处是减少了一次缩进,不过看起来就没有那么清晰了,喜欢哪一种可以自己决定。

expect_before在这个语句以下的所有expect语句之前,首先做一次匹配,使用这个命令需要小心,首先来看例子:expect {eof eofproc―login:‖{send ―$user\r‖}}expect {eof eofproc―password‖{send ―$password\r‖}}expect {eof eofproc―$prompt‖{send ―$cmd\r‖}}上面的例子中,每一个expect都有一个eof过程,而且都是首先检查有没有eof 事件,然后再往下检查其他的事件。

对于这种情况,我们可以用下面的语句来代替:expect_before eof eofprocexpect ―login:‖{send ―$user\r‖}expect ―password‖{send ―$password\r‖}expect ―$prompt‖{send ―$cmd\r‖}expect_after与上面的expect_before一样,不过expect_after是用于在expect语句后面做匹配的,比如下面的语句:expect {―login:‖{send ―$user\r‖}eof eofproc}expect {―password‖{send ―$password\r‖}eof eofproc}expect {―$prompt‖{send ―$cmd\r‖}eof eofproc}就可以用这样的语句来代替:expect_after eof eofprocexpect ―login:‖{send ―$user\r‖}expect ―password‖{send ―$password\r‖}expect ―$prompt‖{send ―$cmd\r‖}看起来简单,但是还有一些需要注意的地方:1.expect_after或者前面说的expect_before语句,都是对这个命令下面的expect语句产生影响的,比如上面的命令中如果把expect_after放在最后一条,那么中间的login之类的expect都是无效的2.expect_after是在expect命令之后做匹配,所以如果有一个expect eof这样的命令,则expect_after eof是无效的,因为先匹配了expect命令中的eof,比如下面的语句:expect_after eof {puts ―it’s after‖}expect eof {puts ―it’s expect‖}则只能匹配到expect中的那个eof,输出是it’s expect,为什么呢?因为上面的语句代表这样的意思:expect {eof {puts ―it’s expect‖}eof {puts ―it’s after‖}}这样应该很明显了。

3.如果有多个expect_after或者expect_before命令,则第二个命令会替换第一个,比如下面的情况:expect_after ―pat1‖ act1expect p1expect p2expect_after ―pat2‖ act2 ―pat3‖ act3expect p3这种情况下,程序流程首先匹配 p1 pat1 p2 pat1,然后因为第二个expect_after语句的关系,下面的匹配则是p3 pat2 pat3,这里第二个after语句替换了第一个,p3不再匹配pat1了。

4.expect_userexpect_user命令用来匹配从用户那里的输入,之前进行匹配时,都是使用expect命令来匹配程序的输出,但这个命令则可以根据用户的输入进行匹配并完成相应的动作,看看下面的语句:expect_user {-re hello{puts stdout "HELLO"; exp_continue}}这个代码段首先从用户那里获取输入,如果发现输入的是hello字符时,就会激活下面的动作,打印HELLO字符,因为exp_continue命令的存在,这个程序会一直循环下去。

exp_send在上面的介绍中,我们已经看到了exp_send命令的使用,exp_send命令是expect中的动作命令,它还有一个完成同样工作的同胞:send,exp_send命令可以发送一些特殊符号,我们看到了\r(回车),还有一些其他的比如:\n(换行)、\t(制表符)等等,这些都与TCL中的特殊符号相同。

send命令有几个可用的参数:-i 指定spawn_id,这个参数用来向不同spawn_id的进程发送命令,是进行多程序控制的关键参数。

-s s代表slowly,也就是控制发送的速度,这个参数使用的时候要与expect中的变量send_slow相关联exp_continue这个命令一般用在动作中,它被使用的条件比较苛刻,看看下面的例子:spawn ssh root@192.168.0.1expect {-timeout 60-re ―password:‖ {exp_send ―word\r‖; exp_continue}-re ―TopsecOS#‖ { }timeout {puts ―Expect was timeout‖; return} }在这个例子中,可以发现exp_continue命令的使用方法,首先它要处于一个expect命令中,然后它属于一种动作命令,完成的工作就是从头开始遍历,也就是说如果没有这个命令,匹配第一个关键字以后就会继续匹配第二个关键字,但有了这个命令后,匹配第一个关键字以后,第二次匹配仍然从第一个关键字开始。

exp_internal这是一条用来打开Expect调试模式的命令,它可以将整个匹配,操作过程中间发生的事情显示出来,它接受的值包括:非0值(打开调试模式)、0(关闭调试模式)、-f file(将调试内容写入文件),使用起来就像下面这样:spawn ftp 10.11.105.15exp_internal 1expect {-re "Name" {exp_send "ftp\r"; exp_continue}-re "Pass" {exp_send "ftp\r"; exp_continue}-re "ftp>" {exp_send "by\r"}}expect EOF注意上面的exp_internal是放在spawn命令后面的。

如果想将调试信息放入文件,则修改exp_internal 1语句,变成下面的样子:exp_internal -f output.txt 1具体的组合如下:exp_internal 0 关闭诊断模式。

exp_internal 1 开启诊断模式,诊断信息输出到标准输出中。

exp_internal –f file 0 开启诊断模式,诊断信息放入文件但不输出到标准输出。

exp_internal –f file 1 开启诊断模式,诊断信息不光写入文件,也输出到标准输出。

exp_pidexp_pid命令用来获取当前spawn的进程号,他支持-i选项,用来指定具体的spawn进程,使用方法就像像下面这样:set pid [exp_pid –i $spawn_id]send_usersend_user命令用来把后面的参数输出到标准输出中去,默认的send、exp_send命令都是将参数输出到程序中去的,用起来就像这样:send_user ―Please input passwd:‖这个语句就可以在标准输出中打印Please input passwd:字符了。