我有一段代码,只是尝试在远程服务器上执行脚本,如果它失败了,我想跟进电话,想象一下:
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在我的设计示例中打印) - 但第一行应该以{{1}}退出,我希望Ruby会以0
进行交互并显示“Exit Failure” (当然,所以逻辑是错误的,需要翻转三元组) - 但是第二行应该以相反的状态退出,而不是。
我甚至无法在文档中找到有关如何执行此操作的任何内容,我有点担心我可能做错了?!
答案 0 :(得分:71)
我发现以下使用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
希望这有帮助。
答案 1 :(得分:6)
以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
答案 2 :(得分:0)
对于较新版本的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。