Bash 和期望:无法通过 telnet 重新启动路由器

Posted

技术标签:

【中文标题】Bash 和期望:无法通过 telnet 重新启动路由器【英文标题】:Bash and expect: can't reboot router via telnet 【发布时间】:2014-08-18 17:21:46 【问题描述】:

我正在尝试通过expect 通过telnet 连接到D-Link 路由器来重新启动它。 问题是我无法执行(通过期望脚本)路由器支持的任何命令。

首先,我用我的路由器向你展示一个简短的 telnet 会话:

telnet 192.168.1.1
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
BCM96338 ADSL Router
Login: admin
Password: 
> swversion show
EU_3-12-01-1R00.A2pB026.d20m
> logout

Bye bye. Have a nice day!!!
Connection closed by foreign host.

现在我正在尝试使用 Expect 脚本使其自动运行,但无法使其正常工作。这是脚本:

#!/usr/bin/expect -f

#exp_internal 1
set timeout 30

#router username
set name admin

#command to execute
set routercmd "swversion show"

#router password
set pass mypassword

#router IP address
set routerip 192.168.1.1

spawn telnet $routerip
# send username & password
expect "Login: "
send "$name\r"
expect "Password: "
send "$pass\r"
expect "> "
send "$routercmd\r"
expect "> "

当我执行脚本时,它卡在密码提示符处:

./reboot_dut.sh 
spawn telnet 192.168.1.1
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
BCM96338 ADSL Router
Login: admin
Password: 

如果我取消注释 #exp_internal 1 行,我会得到:

./reboot_dut.sh 
spawn telnet 192.168.1.1
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns 6398

expect: does "" (spawn_id exp7) match glob pattern "Login: "? no
Trying 192.168.1.1...
expect: does "Trying 192.168.1.1..." (spawn_id exp7) match glob pattern "Login: "? no


expect: does "Trying 192.168.1.1...\r\n" (spawn_id exp7) match glob pattern "Login: "? no
Connected to 192.168.1.1.
expect: does "Trying 192.168.1.1...\r\nConnected to 192.168.1.1." (spawn_id exp7) match glob pattern "Login: "? no


expect: does "Trying 192.168.1.1...\r\nConnected to 192.168.1.1.\r\n" (spawn_id exp7) match glob pattern "Login: "? no
Escape character is '^]'.
expect: does "Trying 192.168.1.1...\r\nConnected to 192.168.1.1.\r\nEscape character is '^]'." (spawn_id exp7) match glob pattern "Login: "? no


expect: does "Trying 192.168.1.1...\r\nConnected to 192.168.1.1.\r\nEscape character is '^]'.\r\n" (spawn_id exp7) match glob pattern "Login: "? no
BCM96338 ADSL Router

expect: does "Trying 192.168.1.1...\r\nConnected to 192.168.1.1.\r\nEscape character is '^]'.\r\nBCM96338 ADSL Router\r\n" (spawn_id exp7) match glob pattern "Login: "? no
Login: 
expect: does "Trying 192.168.1.1...\r\nConnected to 192.168.1.1.\r\nEscape character is '^]'.\r\nBCM96338 ADSL Router\r\nLogin: " (spawn_id exp7) match glob pattern "Login: "? yes
expect: set expect_out(0,string) "Login: "
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "Trying 192.168.1.1...\r\nConnected to 192.168.1.1.\r\nEscape character is '^]'.\r\nBCM96338 ADSL Router\r\nLogin: "
send: sending "admin\r" to  exp7 

expect: does "" (spawn_id exp7) match glob pattern "Password: "? no
a
expect: does "a" (spawn_id exp7) match glob pattern "Password: "? no
dmin
Password: 
expect: does "admin\r\nPassword: " (spawn_id exp7) match glob pattern "Password: "? yes
expect: set expect_out(0,string) "Password: "
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "admin\r\nPassword: "
send: sending "mypassword\r" to  exp7 

expect: does "" (spawn_id exp7) match glob pattern "> "? no
expect: timed out
send: sending "swversion show\r" to  exp7 

expect: does "" (spawn_id exp7) match glob pattern "> "? no

> swversion show

expect: does "\r\n> swversion show\r\n" (spawn_id exp7) match glob pattern "> "? yes
expect: set expect_out(0,string) "> "
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "\r\n> "

【问题讨论】:

是的,看起来卡住了。尝试autoexpect 会话,看看生成的脚本是什么样子的。 这里是pastebin.com/fLVf2wL9。奇怪的事实是,如果我尝试执行 autoexpect 生成的期望脚本,它会再次卡住...... 【参考方案1】:

我想说您需要将提示符与“>”相匹配,而不是“>”(即后面没有空格)。

【讨论】:

它不打印命令的返回值。这是一个带有调试信息的 pastebin,上面印有按照您的建议修改的脚本 pastebin.com/HsNFc2Ka 有趣...似乎 D-Link 路由器只在您发送第一个命令之后发送提示 。那么,如果您在提供密码后发送 两个 回车符(而不是通常的回车符),会有所帮助吗? send "$pass\r\r",或在单独的发送命令中。 还有一件事...如果我没记错的话,expect 只会将输出打印到通过send 在下一次成功的匹配操作中发送的命令。因此,您没有看到任何输出的原因是因为在您发送命令后没有后续匹配。如果我上面的建议(双 CR)有效,那么您将需要对您的命令执行相同的操作(使用两个 \r),以便在收到命令输出后,expect 将成功匹配。有意义吗? 我试过了,但它总是卡住并说(在获得密码后):期望:“”(spawn_id exp7)是否匹配全局模式“>”?没有 好的,我看到您的问题已随解决方案更新。这是这个 D-Link 路由器的一些奇怪行为。恭喜你成功了。我看到您最终在单独的发送命令中发送了双回车。很高兴它有帮助!【参考方案2】:

解决方案:我找到了问题的解决方案。我试图重新启动的路由器是 D-LINK 2640B。此路由器的工作期望脚本是:

#!/usr/bin/expect -f

spawn telnet ROUTER_IP
match_max 10000
expect *login:*
sleep 2
send -- "USERNAME\r"
expect *assword:*
sleep 2
send -- "PASSWORD\r"
expect *>*
send -- "\r"
expect *>*
send -- "COMMAND\r"
expect *>*
send -- "\r"
expect *>*
send -- "logout\r"

【讨论】:

以上是关于Bash 和期望:无法通过 telnet 重新启动路由器的主要内容,如果未能解决你的问题,请参考以下文章

无法在 bash 脚本期望中发送长命令

从期望脚本导出数据

关于win7启动telnet客户端的服务

Bash Expect Telnet:处理服务器关闭的过早连接

通过 Bash 脚本通过 Telnet 发送命令

用于测试多个地址和端口的 Bash 脚本 telnet