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

Perl脚本调用SSH::Expect偶尔密码验证失败的问题与解决问询

解决Net::SSH::Expect登录时的密码重试问题

问题1:等待完整密码提示符后再发送密码

默认的$ssh->login()方法可能会在设备密码提示符未完全就绪时发送密码,导致验证失败。可以放弃自动登录逻辑,手动控制交互流程,确保精准匹配到密码提示符后再发送密码:

  1. 初始化SSH对象时不要设置password参数,避免自动触发密码发送
  2. 手动启动SSH连接
  3. 显式等待设备返回的密码提示符(根据设备实际输出调整正则)
  4. 匹配成功后再发送密码

示例代码:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:43:15