expect_out(buffer)中包含send的数据

我一直以为在Expect中一旦执行send之后,expect_out(buffer)就会被清空,直到有新的数据被填入,而恰恰就是这些数据被用在expect语句中。而今天在调试时发现的问题却令我大吃一惊,原来expect_out(buffer)不会被自动清空,而expect到的数据很可能不是你真正想要的,非常有可能是历史数据。"expect_out(buffer) has the content of the previous send" 一文也指出了这个问题。

 

 

比如在我的代码中,有如下片段:
set prompt "#"
set lockfile "/root/tmp/.cool.lock" 
send "
if /[ -e $lockfile ]; then
        cat $lockfile
else 
        echo /"COOLID: $coolid/" > $lockfile
        echo DONE!
fi
/r"
sleep 1 ;# necessary
expect {
        timeout {
                puts stderr "WARNING: $ME: cannot verify if the Linux AP is locked by other COOL session!";
                exit 2;
        }
       -re "COOLID: (/[1-9](/[0-9])*).*$prompt" {
                puts stdout "expect_out(buffer)=$expect_out(buffer)"
                puts stdout "expect_out(0,string)=$expect_out(0,string)"
                puts stdout "expect_out(1,string)=$expect_out(1,string)"
                puts stdout "expect_out(2,string)=$expect_out(2,string)"
                puts stdout "expect_out(3,string)=$expect_out(3,string)"
        }
        "DONE!"  ;# do nothing    
}

 

无论$lockfile是否存在,expect总会得到COOLID: 68,而expect_out(buffer)的出如下:

[root@bjvsmcl05 ~]# expect_out(buffer)= 
Last login: Fri Jul 23 09:32:13 2010 from bjbldd
[root@bjvsmcl05 ~]# 
[root@bjvsmcl05 ~]# if [ -e /root/tmp/.cool.lock ]; then
>         cat /root/tmp/.cool.lock
> else 
>         echo "COOLID: 68" > /root/tmp/.cool.lock
>         echo DONE!
> fi
COOLID: 1234
[root@bjvsmcl05 ~]# 
[root@bjvsmcl05 ~]#
expect_out(0,string)=23 09:32:13 2010 from bjbldd
[root@bjvsmcl05 ~]# 
[root@bjvsmcl05 ~]# if [ -e /root/tmp/.cool.lock ]; then
>         cat /root/tmp/.cool.lock
> else 
>         echo "COOLID: 68" > /root/tmp/.cool.lock
>         echo DONE!
> fi
COOLID: 1234

 

由此可见,由于expect_out(buffer)中含有send的echo "COOLID: 68",因此永远都能匹配到这个数据。

由于没有找到一种可以清空expect_out(buffer)的方法,无法实时地将expect_out(buffer)清空。我能想到的解决方法有两种:一是更改send和expect的内容或方式,避免send的内容中出现expect的模式(pattern)。比如在我的程序中把上述代码段改为:
set lockfile "/root/tmp/.cool.lock"   
send "cat $lockfile/r"
expect {
        -re "COOLID: (/[1-9](/[0-9])*)" {
                puts stdout "expect_out(buffer)=$expect_out(buffer)"
                puts stdout "expect_out(0,string)=$expect_out(0,string)"
                puts stdout "expect_out(1,string)=$expect_out(1,string)"
                if { [string compare $expect_out(1,string) $coolid] } {
                        puts stdout "ERROR: $ME: $pcname has been reserverd by COOL session $expect_out(1,string), please choose another Linux PC instead./n"
                        exit 2;
                }
        }
        "cat: $lockfile: No such file or directory*" {
                send "echo /"COOLID: $coolid/" > $lockfile/r"
        }
}

 

就可以正常工作了。
另一种方法是按照"expect_out(buffer) has the content of the previous send"的例子中的方法,set prompt,保持原始代码中send的内容不变,将expect的正则表达式改为 -re "fi(.*)$prompt",如此一来希望的输出就在expect_out(1,string)中了,然后利用string或者lsearch命令对匹配到的数据进行分析。

结论:今后在编写Expect脚本时,不仅要考虑每一步的send/expect,也还要考虑到这一步的expect的内容有可能出现在之前的历史数据中。