Ruby,一个接一个地运行linux命令,通过SSH和LOG一切

我想在Ruby witch net :: ssh中编写代码,在远程linux机器上逐个运行命令并记录所有内容(在linux机器上称为命令,stdout和stderr)。

所以我写函数:

def rs(ssh,cmds) cmds.each do |cmd| log.debug "[SSH>] #{cmd}" ssh.exec!(cmd) do |ch, stream, data| log.debug "[SSH:#{stream}>] #{data}" end end end 

例如,如果我想在远程linux上创建新的文件夹和文件:“。/ everylongdirname / anotherlongdirname / a.txt”,并在该目录中列出文件,并在那里找到firefox(这是愚蠢的一点:P)所以我打电话以上程序是这样的:

 Net::SSH.start(host, user, :password => pass) do |ssh| cmds=["mkdir verylongdirname", \ #1 "cd verylongdirname; mkdir anotherlongdirname, \ #2 "cd verylongdirname/anotherlongdirname; touch a.txt", \ #3 "cd verylongdirname/anotherlongdirname; ls -la", \ #4 "cd verylongdirname/anotherlongdirname; find ./ firefox" #5 that command send error to stderr. ] rs(ssh,cmds) # HERE we call our function ssh.loop end 

在运行上面的代码后,我将获得有关第1行,第2行,第3行,第4行,第5行中执行命令的完整LOG巫婆信息。 问题是linux上的状态,来自cmds数组的执行命令之间没有保存(因此我必须在运行正确的命令之前重复“cd”语句)。 而且我对此并不满意。

我的目的是拥有这样的cmds表:

  cmds=["mkdir verylongdirname", \ #1 "cd verylongdirname", \ "mkdir anotherlongdirname", \ #2 "cd anotherlongdirname", \ "touch a.txt", \ #3 "ls -la", \ #4 "find ./ firefox"] #5 

如您所见,运行每个命令之间的状态是保存在linux机器上(并且在运行正确的命令之前我们不需要重复适当的“cd”语句)。 如何改变“rs(ssh,cmds)”程序来做它和LOG EVERYTHING(comand,stdout,stdin)一样吗?

也许尝试使用ssh通道来打开远程shell。 这应该保持命令之间的状态,因为连接将保持打开状态:

http://net-ssh.github.com/ssh/v1/chapter-5.html

这里还有一篇文章用一些不同的方法做类似的事情:

http://drnicwilliams.com/2006/09/22/remote-shell-with-ruby/

编辑1

好。 我明白你在说什么。 SyncShell已从Net :: SSH 2.0中删除。 但是我发现了这个,看起来它几乎与SyncShell

http://net-ssh-telnet.rubyforge.org/

例:

 s = Net::SSH.start(host, user) t = Net::SSH::Telnet.new("Session" => s, "Prompt" => %r{^myprompt :}) puts t.cmd("cd /tmp") puts t.cmd("ls") # <- Lists contents of /tmp 

Net::SSH::Telnet是同步的,并保留状态,因为它在您的远程shell环境中运行pty。 记得设置正确的提示检测,否则Net::SSH::Telnet一旦调用它就会挂起(它正试图找到提示)。

您可以使用管道代替:

 require "open3" SERVER = "..." BASH_PATH = "/bin/bash" BASH_REMOTE = lambda do |command| Open3.popen3("ssh #{SERVER} #{BASH_PATH}") do |stdin, stdout, stderr| stdin.puts command stdin.close_write puts "STDOUT:", stdout.read puts "STDERR:", stderr.read end end BASH_REMOTE["ls /"] BASH_REMOTE["ls /no_such_file"] 

好的,最后在@Casper的帮助下我得到了程序(maby有人使用它):

  # Remote command execution # t=net::ssh:telnet, c="command_string" def cmd(t,c) first=true d='' # We send command via SSH and read output piece by piece (in 'cm' variable) t.cmd(c) do |cm| # below we cleaning up output piece (becouse it have strange chars) d << cm.gsub(/\e\].*?\a/,"").gsub(/\e\[.*?m/,"").gsub(/\r/,"") # when we read entire line(composed of many pieces) we write it to log if d =~ /(^.*?)\n(.*)$/m if first ; # instead of the first line (which has repeated commands) we log commands 'c' @log.info "[SSH]>"+c; first=false else @log.info "[SSH] "+$1; end d=$2 end end # We print lines that were at the end (in last piece) d.each_line do |l| @log.info "[SSH] "+l.chomp end end 

我们在代码中调用它:

 #!/usr/bin/env ruby require 'rubygems' require 'net/ssh' require 'net/ssh/telnet' require 'log4r' ... ... ... Net::SSH.start(host, user, :password => pass) do |ssh| t = Net::SSH::Telnet.new("Session" => ssh) cmd(t,"cd /") cmd(t,"ls -la") cmd(t,"find ./ firefox") end 

谢谢再见。

这里是Net / ssh的包装文章http://ruby-lang.info/blog/virtual-file-system-b3g

来源https://github.com/alexeypetrushin/vfs

记录所有命令只是覆盖Box.bash方法并在那里添加日志记录