Bash脚本中Expect报错:send: Spawn id exp4 not open问题排查
错误原因及修复方案
核心错误点
- 变量名错误:脚本定义了
ssh_password变量,但Expect代码里用的是未定义的$password,导致发送空密码,SSH连接失败后进程关闭,后续send操作找不到对应的spawn进程,触发send: Spawn id exp4 not open错误。 - 重复定义变量:先后两次定义
ub_serv_ip和ssh_username,后定义的值会覆盖之前的,实际连接目标可能和预期不符。 - 提示符匹配不准确:用
expect "$ "匹配命令提示符,不同用户的终端提示符可能是#、$无空格等格式,匹配失败会导致超时等待。 - 输出提取逻辑有误:直接取
expect_out(buffer)会包含输入的命令(如hostname)和输出内容,无法得到纯净的结果。
修复后的完整脚本
#!/bin/bash expect_ssh() { # 配置连接参数,按需修改,避免重复定义 local ub_serv_ip="192.168.233.132" local ssh_username="administrator" local ssh_password="Password123!" # 本地测试时可注释上面三行,启用下面两行 # local ub_serv_ip="127.0.0.1" # local ssh_username="nkloney" local script=$(expect <<EOF set timeout 10 # 设置超时时间,避免长时间无响应 spawn ssh $ssh_username@$ub_serv_ip expect { "*assword:" { send "$ssh_password\r" } # 使用正确的密码变量 "Are you sure you want to continue connecting*" { # 处理首次连接的指纹确认 send "yes\r" exp_continue # 继续等待密码提示 } } # 匹配通用提示符,适配$、#结尾的终端环境 expect -re {\$|#} send "hostname\r" expect -re {\$|#} # 提取纯净的hostname输出:取换行分割后的倒数第二行 set hostname [string trim [lindex [split \$expect_out(buffer) "\n"] end-1]] send "hostname -i\r" expect -re {\$|#} set ip_address [string trim [lindex [split \$expect_out(buffer) "\n"] end-1]] send "exit\r" expect eof puts \$hostname puts \$ip_address EOF ) local hostname=$(echo "$script" | sed -n '1p') local ip_address=$(echo "$script" | sed -n '2p') export SERVER_HOSTNAME="$hostname" export SERVER_IP_ADDRESS="$ip_address" } expect_ssh echo "Server Hostname: $SERVER_HOSTNAME" echo "Server IP Address: $SERVER_IP_ADDRESS"
关键修复说明
- 修正密码变量引用,确保发送正确的SSH密码。
- 添加首次连接时的指纹确认处理,避免卡在交互提示步骤。
- 使用正则匹配通用提示符,适配不同用户的终端环境。
- 优化输出提取逻辑,通过分割buffer内容获取纯净的命令输出。
- 设置超时时间,缩短无响应时的等待时长。
内容的提问来源于stack exchange,提问作者nkloney
相关产品推荐
相关产品推荐

