2012-03-08 66 views
1

我想從另一個ruby程序執行遠程主機上的交互式shell程序。爲了簡便起見,我們假設我要執行的程序是這樣的:如何在ruby遠程主機上執行交互式shell程序

puts "Give me a number:" 
number = gets.chomp() 
puts "You gave me #{number}" 

是最成功迄今使用一個我從here了該方法。正是這一個:

require 'open3' 
Open3.popen3("ssh -tt [email protected] 'ruby numbers.rb'") do |stdin, stdout, stderr| 
    # stdin = input stream 
    # stdout = output stream 
    # stderr = stderr stream 
    threads = [] 
    threads << Thread.new(stderr) do |terr| 
     while (line = terr.gets) 
      puts "stderr: #{line}" 
     end 
    end 
    threads << Thread.new(stdout) do |terr| 
     while (line = terr.gets) 
      puts "stdout: #{line}" 
     end 
    end 

    sleep(2) 
    puts "Give me an answer: " 
    answer = gets.chomp() 
    stdin.puts answer 


    threads.each{|t| t.join()} #in order to cleanup when you're done. 
end 

的問題是,這是不是「互動」,足以給我,我想執行程序(而不是簡單的numbers.rb)具有輸入的多了很多/輸出。你可以把它想象成一個apt-get install,它會問你一些輸入來解決一些問題。
我已閱讀關於net :: ssh和pty,但無法看到他們是否會成爲我期待的(簡單/優雅)解決方案。

理想的解決方案是使用戶不會意識到IO是在遠程主機上完成的:stdin轉到遠程主機stdin,遠程主機的stdout轉到我和我展示它。

如果您有任何想法,我可以嘗試我會很樂意聽到他們。謝謝!

+0

您是否嘗試過使用Net :: SSH? – tadman 2012-03-08 15:47:05

+0

我已經看到了on_data方法來獲取輸出。問題是我不想執行一個命令並獲得它的輸出。我想執行一個命令,顯示它的輸出,從用戶那裏得到輸入,顯示更多的輸出等。 我不明白net :: ssh(或其他)如何做到這一點。 – dcere 2012-03-08 16:34:32

+1

回覆:*理想的解決方案是讓用戶不會意識到IO是在遠程主機上完成的:stdin轉到遠程主機stdin,遠程主機的stdout轉到我和我展示它*實現這一點的方法是'ssh user @ remote program'。沒有本地的Ruby程序來阻礙透明度。 :) – Kaz 2012-03-08 21:06:13

回答

6

試試這個:

require "readline" 
require 'open3' 

Open3.popen3("ssh -tt [email protected] 'ruby numbers.rb'") do |i, o, e, th| 


    Thread.new { 
    while !i.closed? do 
     input =Readline.readline("", true).strip 
     i.puts input 
    end 
    } 

    t_err = Thread.new { 
    while !e.eof? do 
     putc e.readchar 
    end 
    } 

    t_out = Thread.new { 
    while !o.eof? do 
     putc o.readchar 
    end 
    } 

    Process::waitpid(th.pid) rescue nil 
    # "rescue nil" is there in case process already ended. 

    t_err.join 
    t_out.join 

end 

我得到了它的工作,但不要問我爲什麼它的工作原理。這主要是試驗/錯誤。

替代方案:

  • 使用的Net :: SSH,你需要使用:on_process和主題:ruby net/ssh channel dies?不要忘記添加session.loop(0.1)。更多信息在鏈接。 Thread /:on_process的想法激發了我爲自己使用編寫一個gem:https://github.com/da99/Chee/blob/master/lib/Chee.rb
  • 如果你的Ruby程序中的最後一次調用是SSH,那麼你可以使用exec ssh -tt [email protected] 'ruby numbers.rb'。但是,如果你仍然想要User<->Ruby<->SSH之間的交互性,那麼以前的選擇是最好的。
+0

這是一段如此有用的代碼。感謝您創建和分享此內容。 – 2013-05-07 06:16:39

+0

這實際上並不能達到與shell完全交互所需的程度。例如,某些命令可能需要vi(m)才能打開並允許編輯文檔,而這不會處理該文檔。儘管如果Ruby可以處理它,但我認爲很多時候只要在bash中編寫shell腳本會更安全,如果您需要這種交互級別的話。 – 2014-12-31 17:40:58

相關問題