Perl脚本调用SSH::Expect偶尔密码验证失败的问题与解决问询
解决Net::SSH::Expect登录时的密码重试问题
问题1:等待完整密码提示符后再发送密码
默认的$ssh->login()方法可能会在设备密码提示符未完全就绪时发送密码,导致验证失败。可以放弃自动登录逻辑,手动控制交互流程,确保精准匹配到密码提示符后再发送密码:
- 初始化SSH对象时不要设置
password参数,避免自动触发密码发送 - 手动启动SSH连接
- 显式等待设备返回的密码提示符(根据设备实际输出调整正则)
- 匹配成功后再发送密码
示例代码:
my $ssh = Net::SSH::Expect->new ( host => $deviceIpAddr, timeout => 5, # 适当延长超时,适配设备响应速度 log_stdout => 1, user => $username, ssh_option => '-o UserKnownHostsFile=/dev/null', ); # 启动SSH连接 $ssh->run_ssh(); # 等待密码提示符,匹配常见的"Password:"格式(忽略大小写) my $prompt_match = $ssh->expect(5, [qr/Password:\s*$/i]); if ($prompt_match) { # 确认提示符出现后发送密码 $ssh->send($passwd); # 等待登录成功后的shell提示符(根据你的设备调整正则,比如$、#、>) my $login_confirm = $ssh->expect(5, [qr/\$|#|>/]); }
问题2:自动处理第二次密码提示符
可以通过多分支匹配+循环重试的方式,捕获登录失败后的二次密码请求,实现自动重发密码:
示例代码:
my $ssh = Net::SSH::Expect->new ( host => $deviceIpAddr, timeout => 5, log_stdout => 1, user => $username, ssh_option => '-o UserKnownHostsFile=/dev/null', ); $ssh->run_ssh(); my $max_retry = 2; # 设置最大重试次数 my $login_success = 0; while ($max_retry-- > 0 && !$login_success) { # 同时监听三种情况:登录成功提示符、密码提示符、登录失败提示 my $match = $ssh->expect(5, [qr/\$|#|>/ => sub { $login_success = 1; }], # 匹配到登录成功的shell提示符 [qr/Password:\s*$/i => sub { $ssh->send($passwd); }], # 匹配到密码提示,发送密码 [qr/Permission denied/i => sub { # 捕获登录失败,等待下一次密码提示并重发 $ssh->expect(5, qr/Password:\s*$/i); $ssh->send($passwd); }] ); } if (!$login_success) { die "登录失败,已达到最大重试次数"; }
额外提示
- 请根据设备实际输出调整正则表达式(比如部分设备密码提示为
Login password:) - 开启
log_file参数记录交互日志,方便排查问题:log_file => 'ssh_login_debug.log' - 超时时间可根据设备网络延迟适当调整,避免因响应慢导致匹配失败
内容的提问来源于stack exchange,提问作者Jason M
相关产品推荐
相关产品推荐

