问题
I want work on a remote machine within a SSH session:
- login on the remote server
- su
- make my work
With my script a can do step 1 and 2 works. While executing the su command, I can send the password, and got the answer I'm expecting (
on_data: data = gis@v04ree:~>
got gis@v04ree:~>
But then, what should I do? I'm sitting on my channel, nothing happens. How can I make the channel understand that the command has finished and that I want to make my wor on the remote machine?
require 'net/ssh'
require 'net/sftp'
class Connection
def connect
host = 'host'
user = 'user'
#1. Login
Net::SSH.start(host, user) do |ssh|
puts ssh.exec!("whoami")
#2. su
begin
puts(su(ssh, "otherUser", "otherPwd"))
rescue Exception => e
puts e
end
#3. work
puts "logged in as " << ssh.exec!("whoami")
ssh.close
end
end
def su(ssh, user, pwd)
channel = ssh.open_channel do |ch|
channel.request_pty do |ch, success|
raise "Could not obtain pty (i.e. an interactive ssh session)" if !success
end
command = "su - #{user}\n"
puts "command = #{command}"
channel.exec command do |ch, success|
raise "could not execute command" unless success
# "on_data" is called when the process writes something to stdout
ch.on_data do |c, data|
puts "on_data: data = "+data
if data == "Password: "
puts "Password request"
channel.send_data "#{pwd}\n"
end
if data == "gis@v04ree:~> "
#logged in as gis
puts "got gis@v04ree:~>"
#and now? What's next?
#channel.eof! # <-doesn't work
ch.exec "ls" do |ch, success| #<- doesn't work either: success is false
unless success
puts "alas! the command could not be invoked!"
end
end
end
end
#wouldn't be called
ch.on_extended_data do |c, type, data|
puts "on_extended_data: data = #{data}"
end
end #end su - gis
#which statement
ssh.loop
#channel.wait
end
end
end #class end
Connection.new.connect
回答1:
The problem is that su
is creating a subshell, and net-ssh
is controlling the outermost shell. Its just like running... emacs
or something from net-ssh
, you can't expect net-ssh
to be able to know how to control that inner shell.
So what you have to do is when you detect su
was successful, you have to send the data as if you were just typing it in, and then you can read the stdout. Unfortunately, you can't separate the stdout
from the stderr
since its in a subshell, but you can still get the output.
Instead of using ch.exec
after su
ing successfully, use ch.send_data "command\n"
and read the output. Don't forgot to end everything with a ch.send_data "exit\n"
. (Note that \n
has to follow every command to simulate an enter keypress in the console)
来源:https://stackoverflow.com/questions/3061648/ruby-ssh-interactive-command-su-how-further-after-successfull-logged-in