Question

I'm trying to connect, using Net::SSH, to a server that immediately after login executes a script that requires input from user. The user has to enter "1" or "2" and will receive some data via in the terminal afterwards.

My problem is that, although I am able to connect, I can not figure out a way to send "1\n" to the server and to receive the output.

The following code stops at "INFO -- net.ssh.connection.session[80906b74]: channel_open_confirmation: 0 0 0 32768".

Using channel.exec( "1\n" ) instead of channel.send_data unsurprisingly does not work either.

Net::SSH.start('host', 'user', :password => "pass", :auth_methods => ["password"], :verbose => :debug) do |session|

  session.open_channel do |channel|

    channel.on_data do |ch, data|
      STDOUT.print data
    end 

    channel.send_data( "1\n")

  end

  session.loop
end    

Any ideas, anyone?

Thanks in advance

Was it helpful?

Solution

Can you verify that your send_data call is happening after you get the prompt from the remote server? Try constructing a channel.on_data block around your send_data call so that you can verify that you get the expected prompt from the server before you send a response.

You might not want to be using exec here. From the docs for Net::SSH::Connection::Channel:

Sends a channel request asking that the given command be invoked.

You are wanting to send a text string to reply to a prompt, not invoke a command. The docs show exec being used to send full CLI commands like "ls -l /home".

Instead, send_data is probably what you want. The docs show it used to send arbitrary text such as channel.send_data("the password\n"). Note, however, this sentence in the docs:

Note that it does not immediately send the data across the channel, but instead merely appends the given data to the channel‘s output buffer, preparatory to being packaged up and sent out the next time the connection is accepting data.

You might want to take a look at channel.request_pty. It appears to be designed for interaction with a console-based application.

If you are trying to (in essence) script an SSH session that you would normally do manually, you may find it easier to use an expect-like interface (for example, a gem like sshExpect might be worth a try).

OTHER TIPS

Thank you all for the pointers. I have been able to put my finger on the problem – besides using channel.request_pty it was also necessary to request a shell. The following finally works as expected:

Net::SSH.start('host', 'user', :password => "pass", :auth_methods => ["password"]) do |session|

  session.open_channel do |channel|

    channel.request_pty do |ch, success| 
      raise "Error requesting pty" unless success 

      ch.send_channel_request("shell") do |ch, success| 
        raise "Error opening shell" unless success  
      end  
    end

    channel.on_data do |ch, data|
      STDOUT.print data
    end 

    channel.on_extended_data do |ch, type, data|
      STDOUT.print "Error: #{data}\n"
    end

    channel.send_data( "1\n" )

    session.loop
  end  
end    

I'm not terribly familiar with the Net::SSH libs so I can't help with that per-se but it sounds like you could achieve what you want using Capistrano.

For example I have a capistrano task which connects to a remote server, runs a command which expects input and then continues. Capistrano takes care of the remote i/o. Maybe that could be a solution for you?

Hope it helps!

If I execute "1\n" in a shell the reply I get is: bash: 1: command not found

If I execute echo "1" I get: 1

Are you sure you want to try to execute the text you are sending? Maybe you were looking for something like:

output = ""
Net::SSH.start('host', 'user', :password => "pass") do |ssh|
   output = ssh.exec! "echo 1"
end
puts output

I'm not proficient with that lib, but on SSH you can open multiple channels. Maybe the server only responds to the first default channel and if you open another one you get a fresh shell.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top