您的位置:首页 > 编程语言 > PHP开发

【翻译】exploring_expect Chapter 7. Debugging Patterns And Controlling output 调试模式和输出控制

2013-06-16 19:10 459 查看
在本章,我将讨论the generation and suppression of输出的确定类型,包括正常和诊断输出.诊断输出包括一些信息,这些信息对调试模式匹配问题是有帮助的。

我将讨论脚本控制流的调试在整个18章(p399)

7.1 调试模式

在上几章,我描述怎么写模式.显然,你需要知道一些技巧。对一些情况,写有效的模式是一门挑战性的艺术

首先,你要知道一些构建模式的规则。第二,你要理解用tcl表达这些规则。第三,你要知道你表达的字符串的特点

误解任何一步,使你写的模式不能匹配

当模式没有向预想的匹配,一个普遍的特征是脚本执行慢。如,下面是一个登陆的脚本部分。它本应该快速执行。

expect "Login: "

send "don\r"

expect "Password: "

send "swordfish\r"

然而,在一个普通的系统上这段代码要执行20秒而不是1,2秒。有两个问题。第一是模式。第一个模式说expect "Login:"

但是在一个普通的unix系统的提示符是"login:"(注意大小写和空格)

没有匹配,取而代之的是,脚本等待10秒,等待更多的输入,以便匹配(因为缺省超时是10s).在10s后,expect 超时。

因为没有timeout 处理(action),用户没有被告知以致模式匹配失败。expect简单返回并且控制传递到脚本的下一个命令。

这种错误不是不普遍。部分是unix 系统的原因,缺省的登录提示符,以一个小写字母开始同时密码提示符以一个大写字母开始。

这种不兼容性,在很多交互的接口,它被大多数用户忽略并自然显出向上面的脚本

第二个问题是由于另一个不兼容的用户接口,这是一个在password结尾的空格字符模式。但是实际的提示符收到的是“Password:”,

它在结尾没有一个空格。这类不正确的模式是一个简单的错误去做,因为大多数提示符包括一个结尾空格-但是

-但是不是为密码的。重复早先的逻辑,脚本又等了10s

脚本带着这些错误可能工作,但是速度迟缓。有一种方面找到问题是问expect内部正在做什么

命令"exp_internal 1" 引起expect 打印诊断,它描述了内部的一些操作。在其他的事情中,包括expect命令中的对比。

下面是使用"exp_internal 1"并随一个telnet 命令

spawn telnet uunet.uu.net

exp_internal 1

expect "Login: "

send "don\r"

expect "Password: "

send "swordfish\r"

当通过第一个expect-send顺序运行,输出向如下开始:

spawn telnet uunet.uu.net

expect: does "" (spawn_id 5) match glob pattern "Login: "? no

Trying

expect: does "Trying " (spawn_id 5) match glob pattern "Login: "? no

192.48.

expect: does "Trying 192.48." (spawn_id 5) match glob pattern "Login:

"? no

96.2 ..

expect: does "Trying 192.48.96.2 .." (spawn_id 5) match glob pattern

"Login: "? no

你看到的是来自expect的普通的输出加上确切描述缓存内容的输出和当前的模式。

每行从"expect: does"开始。当前的输出缓存,用括号括起。

例如:expect初始在缓存中什么也没有,所以你看见

expect: does "" (spawn_id 5) match glob pattern "Login: "? no

然后,字符串 “Trying" 到达。这是部分字符串,telnet正常打印同时它打开一个connection。

expect添加这个到输入buffer 并且重试模式

expect: does "Trying " (spawn_id 5) match glob pattern "Login: "? no

在每次测试之后,expect print word “no” 如果匹配不成功,如果成功将print yes

(spawn_id 5) 是一个指示,它引起进程参与匹配。我将描述在第10章(p229)中描述特殊意义

现在,我假设仅仅有一个process,并且我将忽略本例子的剩余部分的进程标识符

略过开头,你能最终找到Uunet's问候消息

UUNET Communications Services (uunet)

expect: does "Trying 192.48.96.2 ...\r\nConnected to

uunet.uu.net.\r\nEscape

character is `^]'.\r\n\r\nUUNET Communications Services (uunet)\r\n\r\

r\n\r"

match glob pattern "Login: "? no

通知输入buffer已经被转变成怎样的一种反斜杠代表。即,回车是\r 换成是\n。

如果你需要精确匹配,这是非常有用的

立刻之后,Uunet发送它的登录提示符-脚本正等待的

ogin:

expect: does "Trying 192.48.96.2 ...\r\nConnected to

uunet.uu.net.\r\nEscape

character is '^]'.\r\n\r\nUUNET Communications Services (uunet)\r\n\r\

r\n\rlogin: "

match glob pattern "Login: "? no

现在你能看见login的提示符。它变成显然模式将从来不匹配。

expect参加剩的时间,然后最终report timeout

expect: timed out

send: sent "don\r"

第二个命令简单处理消息描述。在这个case中,它发送字符串don\r 回到进程

现在脚本发送用户名,它立刻进入下一步---等待密码提示符

expect: does "Trying 192.48.96.2 ...\r\nConnected to

uunet.uu.net.\r\nEscape

character is '^]'.\r\n\r\nUUNET Communications Services (uunet)\r\n\r\

r\n\rlogin:

" match glob pattern "Password: "? no

don

expect: does "Trying 192.48.96.2 ...\r\nConnected to

uunet.uu.net.\r\nEscape

character is '^]'.\r\n\r\nUUNET Communications Services (uunet)\r\n\r\

r\n\rlogin:

don\r\n" match glob pattern "Password: "? no

这时候,密码没有出现。出现的是脚本早期发送的用户名。你看见用户名简单的返回因为远端正在回声。

这很正常而且它是为什么你看见你的大多数的键盘击键当你敲键盘的时候

相比之下,密码将不会显

Password:

expect: does "Trying 192.48.96.2 ...\r\nConnected to

uunet.uu.net.\r\nEscape

character is '^]'.\r\n\r\nUUNET Communications Services (uunet)\r\n\r\

r\n\rlogin:

don\r\nPassword:" match glob pattern "Password: "? no

expect: timed out

send: sent "swordfish\r"

你现在能清楚的在输入buffer综合那个包含"password:"---没有一个空格---但是模式正在寻找“Password:"---带一个空格。

模式失败匹配过程。如果你仔细看,你甚至能看见login 提示符仍然在输入buffer中。那是因为它从来没有匹配并且也从来

没从buffer中移除

当前expect命令甚至timeout,并且脚本继续下一行。如果脚本的剩余部分工作,在开始的错误不合计太多;

然后,他们真的应该被修复。至少,他们不必须要的减慢了脚本。最坏,脚本能偶尔发送东西当他们没有意思的时候,

用不可预测的行为和不稳定的脚本结束。当你写脚本的时候请记得。如果你的脚本等大量的时间,甚至当提示符到来的时候,大多数可能

有错误发生,你应该调查。

这是另一个脚本版本,它是值得学习的,因为与执行直线脚本不同。直线脚本严格的一个命令接一个命令。

在这个脚本,有一个while循环,包括一个单一的expect命令。

在一些情况下,这种进程是非常有用的对简单的全部控制当添加灵活性,

但是在11章(p225)我将展示比较好的节省你多次写timeout

更主要的是,模式这次是正确的。诊断输出将展示两种模式匹配同每次的相同输入,并且最终

一种模式将总是被匹配。我也添加了-indices flag (see Chapter 5 (p. 123)).以便你能看见它的效果

spawn telnet ftp.uu.net

exp_internal 1

set timeout 30

while 1 {

expect {

-indices "login: " {

send "don\r"

} -indices "Password:" {

send "swordfish\r"

} timeout {

puts "warning: timed out"

}

}

}

脚本开始和以前的方式相同:靠spawning 一个telnet 进程

spawn telnet ftp.uu.net

expect: does "" match glob pattern "login: "? no

"Password:"? no

expect 通过试图匹配两种模式开始而不是空buffer,因为没什么被立刻收到。

他们都失败了。字符串"trying" 到达并且一些更多的输入运球突破。

在每种例子中,模式失败匹配

Code View: Scroll / Show All

Trying

expect: does "Trying " match glob pattern "login: "? no

"Password:"? no

192.48.96.9 ...

expect: does "Trying 192.48.96.9 ...\r\n" match glob pattern "login:

"? no

"Password:"? no

Connect

expect: does "Trying 192.48.96.9 ...\r\nConnect" match glob pattern

"login: "? no

"Password:"? no

ed to f

expect: does "Trying 192.48.96.9 ...\r\nConnected to f" match glob

pattern "login:

"? no

"Password:"? no

tp.uu.net.

Escape character is `^]'.

expect: does "Trying 192.48.96.9 ...\r\nConnected to

ftp.uu.net.\r\nEscape character

is `^]'.\r\n" match glob pattern "login: "? no

"Password:"? no

最终,你能看见Uunet's问候消息。脚本仍然在需找“login:”(and "Passoword:"那点)

Code View: Scroll / Show All

SunOS UNIX (ftp)

expect: does "Trying 192.48.96.9 ...\r\nConnected to

ftp.uu.net.\r\nEscape character

is `^]'.\r\n\r\n\r\nSunOS UNIX (ftp)\r\n\r\r\n\r" match glob pattern

"login: "? no

"Password:"? no

login:

expect: does "Trying 192.48.96.9 ...\r\nConnected to

ftp.uu.net.\r\nEscape character

is `^]'.\r\n\r\n\r\nSunOS UNIX (ftp)\r\n\r\r\n\rlogin: " match glob

pattern "login:

"? yes

这是第一个成功匹配。expect打印yes 在匹配模式之后,然后打印内部分配,分配在任何action执行被做之前

expect: set expect_out(0,start) "103"

expect: set expect_out(0,end) "109"

expect: set expect_out(0,string) "login: "

expect: set expect_out(buffer) "Trying 192.48.96.9 ...\r\nConnected to

ftp.uu.net.\r\nEscape character is `^]'.\r\n\r\n\r\nSunOS UNIX

(ftp)\r\n\r\r\n\rlogin: "

现在对应的行为被执行,发送字符串don\r 给进程

send: sent "don\r"

expect: does "" (spawn_id 5) match glob pattern "login: "? no

"Password:"? no

don

expect: does "don\r\n" (spawn_id 5) match glob pattern "login: "? no

"Password:"? no

Password:

expect: does "don\r\nPassword:" match glob pattern "login: "? no

"Password:"? yes

expect: set expect_out(0,start) "7"

expect: set expect_out(0,end) "15"

expect: set expect_out(0,string) "Password:"

expect: set expect_out(buffer) "don\r\nPassword:"

send: sent "swordfish\r"

Uunet 反应用一个password提示符。 这是脚本的立刻匹配并且密码被发回

你可以注意到,脚本没有做任何不同的事情在发送密码之后。这是十分无语----它仅仅不断寻找"login:" or "Password:"

无论它是否登录成功。尽管如此,它足以显示诊断,他们来自exp_internal命令

在第6章(p151),我描述-notransfer 标记。一起,-notransfer标记和内部诊断应该非常有用对调试你遇到大多数模式问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: