Solaris 11.4下Expect脚本实现SSH密钥已安装检测的技术问询
我来帮你解决这个问题——在Solaris 11.4上用Expect脚本实现SSH公钥自动部署,并且跳过已经存在密钥的服务器。你的核心痛点是没法正确识别"无密码登录成功"的状态,之前匹配空字符串的思路确实会导致误匹配,下面给你一套完整的解决方案:
核心思路调整
与其先尝试部署再判断,不如先验证目标服务器是否已经接受公钥:发起一个无密码SSH请求,执行一个简单的测试命令(比如输出一段标识文本)。如果能成功执行,说明密钥已存在,直接跳过;如果遇到密码提示/主机密钥确认,再执行密钥部署操作。
修改后的完整脚本
#!/usr/bin/expect set timeout 1200 set user [lindex $argv 0] set host [lindex $argv 1] set pass [lindex $argv 2] # 读取本地公钥并去除末尾换行符,避免写入时产生多余空行 set sshkeyfile [open ~/.ssh/id_rsa.pub r] set sshid [string trimright [read $sshkeyfile] "\n"] close $sshkeyfile # 第一步:尝试无密码登录,验证密钥是否已配置 spawn ssh $user@$host "echo 'KEY_VERIFIED_SUCCESS'" expect { # 处理首次登录的主机密钥确认提示 "continue connecting (yes/no/[a-zA-Z0-9:]+)?" { send "yes\r" exp_continue } # 出现密码提示:说明密钥未配置,需要部署 "Password:" { # 中断当前无效的SSH会话(发送Ctrl+C) send "\003" expect eof # 执行密钥部署命令:先检查密钥是否已存在,不存在再追加 spawn ssh $user@$host "mkdir -m 700 ~/.ssh 2>/dev/null; grep -q '$sshid' ~/.ssh/authorized_keys 2>/dev/null || echo '$sshid' >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys" expect { "continue connecting (yes/no/[a-zA-Z0-9:]+)?" { send "yes\r" exp_continue } "Password:" { send "$pass\r" expect eof puts "✅ Successfully deployed key to $host" } timeout { puts "❌ Timeout when deploying key to $host" exit 1 } } } # 成功获取测试输出:说明密钥已存在,直接跳过 "KEY_VERIFIED_SUCCESS" { expect eof puts "ℹ️ Key already exists on $host, skipping" exit 0 } # 错误处理:超时或意外断开连接 timeout { puts "❌ Timeout connecting to $host" exit 1 } eof { puts "❌ Unexpected connection closed to $host" exit 1 } }
关键细节说明
- 精准匹配登录成功状态:用自定义的
KEY_VERIFIED_SUCCESS输出作为登录成功的标识,完全避免了空字符串匹配的误判问题。 - 双重校验避免重复写入:部署密钥时,通过
grep -q '$sshid' ~/.ssh/authorized_keys先检查密钥是否已存在,只有不存在时才追加写入,进一步确保幂等性。 - 健壮的会话管理:遇到密码提示时,先发送
Ctrl+C中断当前会话,再启动新的部署会话,避免残留无效进程。 - 友好的状态提示:用
✅/ℹ️/❌区分不同操作结果,批量部署时更容易排查问题。
调试技巧
如果脚本运行不符合预期,可以用Expect的调试模式查看匹配过程:
expect -d your_script.exp username target_host password
内容的提问来源于stack exchange,提问作者AndyM
相关产品推荐
相关产品推荐

