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

Ruby带交互式登录提示的SSH命令执行异常排查

问题分析与解决

你的代码有两个核心问题导致无法获取输出和sudo请求:

  • 缺少SSH会话事件循环:Net::SSH的通道事件(比如接收远程输出)需要通过session.loop来驱动处理,你的代码在发送命令后直接结束了会话,根本没等远程返回数据就退出了。
  • 没有处理交互式输入逻辑:发送sudo whoami后需要输入密码,但你的代码只处理了输出打印,没实现从本地读取输入并发送给远程的逻辑。

下面是修复后的代码:

print('login: ')
user = $stdin.gets.chomp

Net::SSH.start(device_ip, user, port: device_port, verify_host_key: :never) do |session|
  session.open_channel do |channel|
    channel.request_pty do |inner_channel, success|
      raise 'Failed to request pty' unless success

      inner_channel.send_channel_request('shell') do |inner_ch, inner_success|
        raise 'Failed to connect to the device' unless inner_success

        # 处理远程标准输出
        inner_ch.on_data do |_ch, data|
          print(data)
          # 检测到sudo密码提示时,读取本地输入并发送
          if data.include?('[sudo] password for')
            print 'Enter sudo password: '
            password = $stdin.gets.chomp
            inner_ch.send_data("#{password}\n")
          end
        end

        # 处理远程标准错误输出
        inner_ch.on_extended_data do |_ch, type, data|
          print(data) if type == 1 # 1代表标准错误流
        end

        # 发送第一个命令
        inner_ch.send_data("whoami\n")
        # 短暂延迟避免命令堆叠,也可根据whoami的输出完成来触发第二个命令
        sleep 0.5
        inner_ch.send_data("sudo whoami\n")
      end
    end
  end

  # 启动事件循环,保持会话活跃直到通道关闭
  session.loop
end

关键改动说明:

  1. 添加session.loop:让SSH会话持续运行,处理所有通道的数据流事件,直到会话主动关闭。
  2. 增加sudo密码交互逻辑:在on_data回调里识别sudo的密码提示,读取本地输入并发送给远程。
  3. 添加on_extended_data处理错误输出:避免错误信息被遗漏。
  4. 增加短暂延迟:防止两个命令连续发送导致远程shell来不及处理,若要更严谨,可通过判断whoami的输出来触发第二个命令。

内容的提问来源于stack exchange,提问作者rtrrtr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:05:15