代码之家  ›  专栏  ›  技术社区  ›  Lee Hambley

如何使用Ruby的net::ssh库获得退出状态?

  •  31
  • Lee Hambley  · 技术社区  · 14 年前

    我有一小段代码,只是尝试在远程服务器上执行一个脚本,如果失败,我想进行后续调用,想象一下:

    require 'rubygems'
    require 'net/ssh'
    require 'etc'
    
    server = 'localhost'
    
    Net::SSH.start(server, Etc.getlogin) do |ssh|
      puts (ssh.exec("true")  ? 'Exit Success' : "Exit Failure")
      puts (ssh.exec("false") ? 'Exit Success' : "Exit Failure")  
    end
    

    我希望(忽略stdout和stderr是在我的人为示例中打印的)-但是第一行应该退出 0 我希望Ruby能像 false 显示“退出失败”(当然,逻辑错误,三元需要翻转),但第二行应该以相反的状态退出,而不是。

    我甚至在文档中找不到任何关于如何执行此操作的信息,我有点担心自己可能做错了?!

    2 回复  |  直到 8 年前
        1
  •  69
  •   Han    12 年前

    我发现下面使用net::ssh运行进程的方法更有用。它为你提供了独特的 stdout stderr , exit code exit signal .

    require 'rubygems'
    require 'net/ssh'
    require 'etc'
    
    server = 'localhost'
    
    def ssh_exec!(ssh, command)
      stdout_data = ""
      stderr_data = ""
      exit_code = nil
      exit_signal = nil
      ssh.open_channel do |channel|
        channel.exec(command) do |ch, success|
          unless success
            abort "FAILED: couldn't execute command (ssh.channel.exec)"
          end
          channel.on_data do |ch,data|
            stdout_data+=data
          end
    
          channel.on_extended_data do |ch,type,data|
            stderr_data+=data
          end
    
          channel.on_request("exit-status") do |ch,data|
            exit_code = data.read_long
          end
    
          channel.on_request("exit-signal") do |ch, data|
            exit_signal = data.read_long
          end
        end
      end
      ssh.loop
      [stdout_data, stderr_data, exit_code, exit_signal]
    end
    
    Net::SSH.start(server, Etc.getlogin) do |ssh|
      puts ssh_exec!(ssh, "true").inspect
      # => ["", "", 0, nil]
    
      puts ssh_exec!(ssh, "false").inspect  
      # => ["", "", 1, nil]
    
    end
    

    希望这有帮助。

        2
  •  6
  •   Mikey    12 年前

    基于flitzwald的答案-我已经将我的版本修补到net::ssh(Ruby1.9+)中。

    class Net::SSH::Connection::Session
      class CommandFailed < StandardError
      end
    
      class CommandExecutionFailed < StandardError
      end
    
      def exec_sc!(command)
        stdout_data,stderr_data = "",""
        exit_code,exit_signal = nil,nil
        self.open_channel do |channel|
          channel.exec(command) do |_, success|
            raise CommandExecutionFailed, "Command \"#{command}\" was unable to execute" unless success
    
            channel.on_data do |_,data|
              stdout_data += data
            end
    
            channel.on_extended_data do |_,_,data|
              stderr_data += data
            end
    
            channel.on_request("exit-status") do |_,data|
              exit_code = data.read_long
            end
    
            channel.on_request("exit-signal") do |_, data|
              exit_signal = data.read_long
            end
          end
        end
        self.loop
    
        raise CommandFailed, "Command \"#{command}\" returned exit code #{exit_code}" unless exit_code == 0
    
        {
          stdout:stdout_data,
          stderr:stderr_data,
          exit_code:exit_code,
          exit_signal:exit_signal
        }
      end
    end