在expect命令中使用花括号时超时的原因
我正在尝试从Linux机器通过SSH连接到一台Cisco交换机。两者都在GNS3中。
在不带大括号的情况下使用expect和 send语句效果很好。
#!/usr/bin/expect
set timeout 60
spawn ssh admin@[lindex $argv 0]
expect -re "^Password:$"
send -- "admin\r"
interact
使用带大括号时,expect会超时。
!/usr/bin/expect
set timeout 60
spawn ssh admin@[lindex $argv 0]
expect {
-re "^Password:$" {send -- "admin\r"}
timeout {puts "took too much time"; exit}
eof {puts "finished in time"}
}
interact
对于上述脚本,屏幕上会打印出“took too much time”并且脚本会退出。
我有兴趣使用 expect 在多种选项之间进行选择并执行路由器命令。为此我需要使用大括号 { }
有人知道这是为什么会这样吗?
解决方案
在 expect 脚本中,默认行为是,如果 expect 命令没有自定义超时处理程序,且在匹配之前发生超时,其结果通常是直接返回。你第一个示例几乎可以肯定是这样的情况——正则表达式没有比第二个示例多出多少匹配。我猜如果把超时改成 -1使其无限,则第一个脚本会挂起,永远来不及执行任何 send 的操作。
其原因在于 ^ 和 $ 锚点——默认在 tcl 正则表达式中,它们不会匹配 行 的起始和结束,而是匹配输入整体的起始和结束,这很可能(我没有机会去确认,因为我没有Cisco硬件)包含的不止是 'Password:'。这就是为什么你通常会看到像这样的内容:
expect {
Password: { send -- "admin\r" }
timeout { puts "took too much time"; exit }
eof { puts "finished in time" }
}
这使用的是未锚定的通配符全局匹配;你也可以使用 -ex Password: 来进行精确的未锚定字符串匹配。
如果你坚持使用正则表达式(尽管在这个简单的情景中并不需要),需要改动两点:
首先,在模式的开头通过一个 (?n) [嵌入式选项] 来开启对换行符敏感的匹配。
演示它是如何改变匹配的:
% regexp {^Password:$} "Welcome to Cisco!\nPassword:\n"
0
% regexp {(?n)^Password:$} "Welcome to Cisco!\nPassword:\n"
1
其次,因为 expect 强制使用CRLF行结束,在对换行符敏感的模式下 $ 会在换行符之前匹配,你需要考虑到那个回车。-re {(?n)^Password:(?:\r?)$} 应该会匹配成功。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。