Copying a File to Another Machine
Problem
You want to programatically send files to another computer, the way the Unix scp command does.
Solution
Use the Net:SSH library to get a secure shell connection to the other machine. Start a cat process on the other machine, and write the file you want to copy to its standard input.
require ubygems require et/ssh def copy_file(session, source_path, destination_path=nil) destination_path ||= source_path cmd = %{cat > "#{destination_path.gsub(", \")}"} session.process.popen3(cmd) do |i, o, e| puts " Copying #{source_path} to #{destination_path}… " open(source_path) { |f| i.write(f.read) } puts Done. end end Net::SSH.start(example.com, :username=>leonardr, :password=>mypass) do |session| copy_file(session, /home/leonardr/scripts/test.rb) copy_file(session, /home/leonardr/scripts/"test".rb) end # Copying /home/leonardr/scripts/test.rb to /home/leonardr/scripts/test.rb… # Done. # Copying /home/leonardr/scripts/"test".rb to /home/leonardr/scripts/"test".rb… # Done.
Discussion
The scp command basically implements the old rcp protocol over a secured connection. This code uses a shortcut to achieve the same result: it uses the high-level SSH interface to spawn a process on the remote host which writes data to a file.
Since you can run multiple processes at once over your SSH session, you can copy multiple files simultaneously. For every file you want to copy, you need to spawn a cat process:
def do_copy(session, source_path, destination_path=nil) destination_path ||= source_path cmd = %{cat > "#{destination_path.gsub(", \")}"} cat_process = session.process.open(cmd) cat_process.on_success do |p| p.write(open(source_path) { |f| f.read }) p.close puts "Copied #{source_path} to #{destination_path}." end end
The call to session.process.open creates a process-like object that runs a cat command on the remote system. The call to on_success registers a callback code block with the process. That code block will run once the cat command has been set up and is accepting standard input. Once that happens, its safe to start writing data to the file on the remote system.
Once youve set up all your copy operations, you should call session.loop to perform all the copy operations simultaneously. The processes won actually be initialized until you call session.loop.
Net::SSH.start(example.com, :username=>leonardr, :password=>mypass) do |session| do_copy(session, /home/leonardr/scripts/test.rb) do_copy(session, /home/leonardr/new_index.html, /home/leonardr/public_html/index.html) session.loop end # Copied /home/leonardr/scripts/test.rb to /home/leonardr/scripts/test.rb # Copied /home/leonardr/new_index.html to /home/leonardr/public_html/index.html
Категории