我想在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)一样吗?
答案 0 :(得分:3)
也许尝试使用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
一旦调用它就会挂起(它正试图找到提示)。
答案 1 :(得分:2)
您可以改用管道:
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"]
答案 2 :(得分:2)
好的,最后在@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
谢谢,再见。
答案 3 :(得分:0)
这里是Net / ssh的包装文章http://ruby-lang.info/blog/virtual-file-system-b3g
来源https://github.com/alexeypetrushin/vfs
记录所有命令只是覆盖Box.bash方法并在那里添加日志记录