2012-03-08 63 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

相关问题