Unix命令可以在服务器上运行,但不能在ruby ssh会话中运行

我正在尝试学习如何将net-ssh gem用于ruby。 我想在登录目录 – / home / james后执行以下命令。

cd / pwd ls 

当我使用putty执行此操作时,它可以工作,我可以看到目录列表。 但是,当我用ruby代码执行它时,它不会给我相同的输出。

 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 

输出 –

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

我期待pwd给我/而不是/ home / james。 这就是它在腻子中的作用。 ruby代码中的错误是什么?

似乎每个命令都在它自己的环境中运行,因此当前目录不会通过exec传递给exec。 如果您这样做,可以validation这一点:

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

它将打印/ 。 从文档中不清楚如何在同一环境中执行所有命令,或者根本不可能。

这是因为net/ssh是无状态的,因此它会在每次执行命令时打开一个新连接。 您可以使用实现此方法的黑麦gem。 但我不知道它是否适用于ruby> 2,因为它的开发并不活跃。

另一种方法是使用pty进程,在其中使用ssh命令打开伪终端,而不是使用输入和输出文件为终端写入命令并读取结果。 要读取结果,您需要使用IO类的select方法。 但是你需要学习如何使用这些实用程序,因为它对于没有经验的程序员来说并不那么明显。

而且,是的,我发现了如何做到这一点,事实上它是如此简单。 我想我上次没有得到这个解决方案,因为我对net-ssh,pty终端的这个东西有点新。 但是,是的,我终于找到了它,在这里和榜样。

 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 == "exit\n" end end threads.each(&:join) 

在这里,我们是一个使用net-ssh ruby​​ gem的交互式终端。 有关更多信息,请查看以前的版本1,但它对于了解每个部分的工作原理非常有用。 在这里