2010-08-02 53 views
30

我有一小段代码,无非是想在远程服务器上执行一个脚本,在失败的情况下,我想提出一个跟进电话,想象一下:如何通过Ruby的Net :: SSH库获取退出状态?

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

我什至不能找到有关如何做到这一点的文档,我有点担心,我可能会做错了吗?!

回答

66

我发现以下使用Net :: SSH运行进程的方式更有用。它为您提供不同的stdoutstderr,exit codeexit 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 

希望这会有所帮助。

+0

哇,太酷了。谢谢。 – sarnold 2010-08-02 09:09:11

+0

flitzwald,这真棒 - 我希望我可以回顾性地添加赏金或其他东西!非常感谢! – 2010-08-02 11:26:58

+0

非常感谢。它完美的作品。这应该在Net :: SSH中。 – 2011-04-19 13:27:58

6

大厦由flitzwald答案 - 我猴子修补我的版本的这一成的Net :: SSH(红宝石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 
+0

你有没有考虑将它作为补丁发送给他们? – 2012-11-19 11:12:47

+0

我目前正在研究一个依赖这个功能的项目 - 一旦我测试完了,我会。在有些情况下,尽管执行成功,退出代码> 0,所以我很可能会将修改提高为可选 – Mikey 2012-11-20 08:37:00

+0

@Mikey这会是什么情况?会不会有一个非零的退出代码,因为shell,ssh或库通信问题,或者该命令是否会返回nonzro退出代码,但完成了它的工作? – Phillipp 2014-08-20 21:53:18