You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:15:55