#!/usr/bin/env ruby require 'rubygems' require 'pty' require 'expect' require 'io/console' hosts_file = ARGV[0] || "hosts" print "Password:" password = $stdin.noecho(&:gets) password.chomp! puts $expect_verbose = true File.open(hosts_file).each do |host| host.chomp! print "Copying id to #{host} ... " begin PTY.spawn("ssh-copy-id #{host}") do |cp_out, cp_in, pid| begin pattern = /#{host}'s password:/ cp_out.expect(pattern, 10) do |m| cp_in.printf("#{password}\n") end cp_out.readlines rescue Errno::EIO ensure Process.wait(pid) end end rescue PTY::ChildExited => e puts "Exited: #{e.status}" end status = $? if status == 0 puts "Done!" else puts "Failed with exit code #{status}!" end end
Thursday, December 27, 2012
Have to read all from Ruby PTY output
I wrote a Ruby script to call ssh-copy-id to distribute my public key to a list of hosts. It took me a while to make it work. The code is simple: read the password, and call ssh-copy-id for each host to copy the public key. Of course, the code doesn't consider all scenarios like the key is already copied, and wrong password. The tricky parts are "cp_out.readlines" and "Process.wait(pid)". If you don't read all the data from cp_out (comment out cp_out.readlines), the spawned process won't return.
Subscribe to:
Post Comments (Atom)
I've spent the last two hours trying to figure out why my code wasn't working. Turns out my exception handling was in the wrong place. Thanks to your code and lines 28 and 29, I suddenly realised why it was failing.
ReplyDeleteThank you so much.