如何使用 Ruby 的 Net::SSH 库获取退出状态?

发布于 09-12 14:20 字数 528 浏览 8 评论 0原文

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

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 并显示“退出失败”(当然,所以逻辑是错误,三元需要翻转) - 但第二行应该以相反的状态退出,但事实并非如此。

我什至在文档中找不到有关如何执行此操作的任何内容,我有点担心我可能做错了?!

I have a snippet of code, simply trying to execute a script on a remote server, in the event that it fails, I'd like to make a follow-up call, imagine this:

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

I would expect (ignoring that stdout and stderr are printed in my contrived example) - but first line should exit with 0 which I would expect Ruby would interperate as false and display "Exit Failure" (sure, so the logic is wrong, the ternary needs to be flipped) - but the second line should exit with the opposite status, and it doesn't.

I can't even find anything in the documentation about how to do this, and I'm a little worried that I might be doing it wrong?!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黑色毁心梦2024-09-19 14:20:23

我发现以下使用 Net::SSH 运行进程的方法更有用。它为您提供了不同的stdoutstderr退出代码退出信号

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

希望这有帮助。

I find the following way of running processes with Net::SSH much more useful. It provides you with distinct stdout and stderr, exit code and 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

Hope this helps.

基于 flitzwald 的答案 - 我已经将我的版本修补到 Net::SSH (Ruby 1.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

Building on the answer by flitzwald - I've monkey patched my version of this into Net::SSH (Ruby 1.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
对你的占有欲2024-09-19 14:20:23

对于较新版本的 Net::SSH,您只需将状态哈希传递给 Net::SSH::Connection::Session#exec:

status = {}

Net::SSH.start(hostname, user, options) do |ssh|
  channel = ssh.exec(command, status: status)
  channel.wait # wait for the command to actually be executed
end

puts status.inspect
# {:exit_code=>0}

默认情况下,exec 会传输其输出到 $stdout$stderr。您可以将一个块传递给 exec 来执行不同的操作,例如:

ssh.exec(command, status: status) do |ch, stream, data|
  if stream == :stdout
    do_something_with_stdout(data)
  else
    do_something_with_stderr(data)
  end
end

这适用于 6.1.0 - 不确定旧版本的可用性。请参阅 http://net -ssh.github.io/net-ssh/Net/SSH/Connection/Session.html#method-i-exec 了解更多详细信息。

For newer versions of Net::SSH, you can just pass a status hash to Net::SSH::Connection::Session#exec:

status = {}

Net::SSH.start(hostname, user, options) do |ssh|
  channel = ssh.exec(command, status: status)
  channel.wait # wait for the command to actually be executed
end

puts status.inspect
# {:exit_code=>0}

By default, exec streams its output to $stdout and $stderr. You can pass a block to exec to do something different, a la:

ssh.exec(command, status: status) do |ch, stream, data|
  if stream == :stdout
    do_something_with_stdout(data)
  else
    do_something_with_stderr(data)
  end
end

This works on 6.1.0 - not sure about availability for older versions. See http://net-ssh.github.io/net-ssh/Net/SSH/Connection/Session.html#method-i-exec for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文