2012-03-08 24 views
1

別のルビープログラムからリモートホスト上で対話型シェルプログラムを実行しようとしています。単純化のための私が実行したいプログラムは、このようなものであると仮定してみましょう:ruby​​からリモートホスト上で対話型シェルプログラムを実行する方法

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

これまでのところ、私はhereからもらったものを使用しているされてきた最も成功したアプローチ。それは、この1:

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に行き、リモートホストからのstdoutは私と私はそれを示します。

あなたは私が試してみることができるアイデアがあれば、私はそれらを聞いて幸せになります。ありがとうございました!

+0

Net :: SSHを試しましたか? – tadman

+0

出力を得るためにon_dataメソッドを見ました。問題は、コマンドを実行してその出力を取得したくないということです。私はコマンドを実行し、その出力を表示し、ユーザーからの入力を取得し、より多くの出力を表示したいと思います。 net :: ssh(または他のもの)でそれを行う方法はわかりません。 – dcere

+1

Re:*理想的な解決方法は、ユーザーがリモートホスト上でIOが実行されていることを認識しないようにすることです。標準入力はリモートホストstdinに行き、リモートホストからのstdoutは私と私はそれを示します。*これを達成する方法は 'ssh user @ remote program'です。透明性のためにローカルのRubyプログラムはありません。 :) – Kaz

答えて

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 

私が働いて、それを得たが、それが動作する理由は聞かないでください。それは主に試行錯誤でした。

代替:

  • ネット:: SSHを使用して、あなたが使用する必要があります。on_processとスレッド:ruby net/ssh channel dies?session.loop(0.1)を追加することを忘れないでください。リンクの詳細。 Thread /:on_processのアイデアは、自分自身のために宝石を書くよう促しました。https://github.com/da99/Chee/blob/master/lib/Chee.rb
  • Rubyプログラムの最後の呼び出しがSSHの場合、exec ssh -tt [email protected] 'ruby numbers.rb'です。しかし、まだUser<->Ruby<->SSHの間にインタラクティブ機能が必要な場合は、前の方法が最適です。
+0

これはとても便利なコードです。これを作成して共有してくれてありがとう。 –

+0

これは、シェルと完全にやりとりするために必要な程度までは実際には機能しません。たとえば、vi(m)を開いて文書の編集を許可するコマンドがありますが、これでは処理できません。 Rubyがそれを処理できるのはうれしいことですが、そのレベルの対話性が必要な場合は、シェルスクリプトをbashで書くことは何度も安全だと思います。 –

関連する問題