如何用Expect(Tcl)判断SSH/Telnet会话是否终止及解决脚本报错
解决Expect脚本登出判断与send报错问题
一、错误原因说明
你遇到的send: spawn id exp6 not open错误,和第6个表达式无关——exp6是Expect给当前远程连接进程分配的内部标识ID,出现这个错误意味着远程服务器已经断开了你的连接,此时再执行send操作自然会失败。
二、核心解决方案:判断服务器是否登出
修改循环内的expect逻辑,同时监听命令提示符和服务器登出/连接断开的提示,一旦匹配到断开信号就终止循环,避免无效的send操作。
调整后的代码示例:
for { set i $index } { $i < $n } { incr i } { expect { -re $prompt { # 匹配到命令提示符,发送当前命令 send "[lindex $array $i]\r" } # 匹配常见的连接断开提示,根据你的服务器实际提示修改正则 -re "(Connection closed by remote host|logout|Connection terminated)" { puts "Remote server has logged out, stopping command execution" break } timeout { # 超时处理,防止脚本无限等待 puts "Timeout: no response from server" break } } }
关键注意点:
- 你需要根据实际服务器的断开提示文本,调整正则表达式的内容,确保能准确匹配到登出信号。
- 加入
timeout分支可以避免脚本因服务器无响应而挂起。
三、你提到的临时去重方案实现
如果要实现仅移除列表末尾连续重复的最后一个元素(比如[foo bar foo foo bar bar]处理后变为[foo bar foo foo bar]),可以用以下Tcl代码:
# 先判断列表长度至少为2,避免索引越界 if {[llength $array] >= 2} { set last_item [lindex $array end] set second_last_item [lindex $array end-1] if {$last_item eq $second_last_item} { # 移除最后一个元素 set array [lrange $array 0 end-1] # 更新命令数量n的值 set n [llength $array] } }
说明:
- 这段代码只会检查列表最后两个元素,仅当它们完全相同时删除最后一个,不会影响列表前面的重复元素。
- 处理后必须更新
$n的值,确保循环次数和实际命令数量一致。
四、额外建议
- 优先采用登出判断的方案,这是从根源上解决问题的方式;临时去重只是特定场景下的规避手段,无法覆盖所有服务器登出情况。
- 调试时可以在
expect分支中加入puts "Matched: $expect_out(buffer)",打印匹配到的服务器输出,方便定位问题。
内容的提问来源于stack exchange,提问作者Lucky
相关产品推荐
相关产品推荐

