Unix commands work on server but not in ruby ssh session

I am trying to learn how to use the net-ssh gem for ruby. I want to execute the commands below, after I login to the directory - /home/james.

cd /
pwd
ls

When I do this with putty, it works and i can see a list of directories. But, when I do it with ruby code, it does not give me the the same output.

require 'rubygems' 
require 'net/ssh'

host = 'server'
user = 'james'
pass = 'password123'

def get_ssh(host, user, pass)
    ssh = nil
    begin
        ssh = Net::SSH.start(host, user, :password => pass)
        puts "conn successful!"
    rescue
        puts "error - cannot connect to host"
    end
    return ssh
end

conn = get_ssh(host, user, pass)

def exec(linux_code, conn)
    puts linux_code
    result = conn.exec!(linux_code)
    puts result
end

exec('cd /', conn)
exec('pwd', conn)
exec('ls', conn)

conn.close

Output -

conn successful!
cd /
nil
pwd
/home/james
ls
nil

I was expecting pwd to give me / instead of /home/james. That is how it works in putty. What is the mistake in the ruby code?


It seems like every command runs on it's own environment, so the current directory is not carried over exec to exec. You can verify this if you do:

exec('cd / && pwd', conn)

It will print / . It is not clear from the documentation how to make all the commands execute on the same environment or if this is even possible at all.


This is because net/ssh is stateless, so it opens a new connection with each command execution. You can use the rye gem that implements a work around for this. but I do not know if it works with ruby > 2, since its development is not that active.

Another way is to use a pty process, in which you'll open a pseudo terminal with the ssh command, than use the input and output files to write commands for the terminal and read the results. To read the results you need to use the select method of the IO class. But you need to learn how to use those utilities since its not that obvious for a non experienced programmer.


And, Yey, I found how to do that, and in fact it is so simple. I think I did not get to this solution last time, because I was a little new to this thing of net-ssh, pty terminal. But yey, I found it finally, and here and example.

require 'net/ssh'

shell = {} #this will save the open channel so that we can use it accross threads
threads = []
# the shell thread
threads << Thread.new do
  # Connect to the server
  Net::SSH.start('localhost', 'your_user_name', password: 'your_password') do |session|
    # Open an ssh channel
    session.open_channel do |channel|   
      # send a shell request, this will open an interactive shell to the server 
      channel.send_channel_request "shell" do |ch, success|    
        if success      
          # Save the channel to be used in the other thread to send commands
          shell[:ch] = ch
          # Register a data event
          # this will be triggered whenever there is data(output) from the server
          ch.on_data do |ch, data|
              puts data
          end  
        end  
      end  
    end  
  end  
end

# the commands thread
threads << Thread.new do
  loop do
    # This will prompt for a command in the terminal
    print ">"
    cmd = gets
    # Here you've to make sure that cmd ends with 'n'
    # since in this example the cmd is got from the user it ends with 
    #a trailing eol
    shell[:ch].send_data cmd
    # exit if the user enters the exit command
    break if cmd == "exitn"
  end
end

threads.each(&:join)

and here we are, an interactive terminal using net-ssh ruby gem. For more info look here its for the previous version 1, but it is so useful for you to understand how every piece works. And here

链接地址: http://www.djcxy.com/p/4310.html

上一篇: 如何在Ruby on Rails中获取当前的绝对URL?

下一篇: Unix命令在服务器上工作,但不在ruby ssh会话中