2012-03-08 4 views
1

Я пытаюсь выполнить интерактивную программу оболочки на удаленном хосте из другой программы ruby. Для простоты предположим, что программа, которую я хочу, чтобы выполнить что-то вроде этого:Как выполнить интерактивную программу оболочки на удаленном хосте от ruby ​​

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

+0

Я видел метод on_data для получения результата. Проблема в том, что я не хочу выполнять команду и получать ее вывод. Я хочу выполнить команду, показать ее вывод, получить вход от пользователя, показать больше вывода и т. Д. Я не вижу, как это сделать с помощью net :: ssh (или других). – dcere

+1

Re: * Идеальное решение заключается в том, чтобы сделать его таким образом, что пользователь не понимает, что IO выполняется на удаленном хосте: stdin отправляется на удаленный хост 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 

Я получил это работает, но не спрашивайте меня, почему это работает. Это было главным образом проб/ошибок.

Альтернативы:

  • Использование Net :: SSH, вы должны использовать: on_process и Thread: ruby net/ssh channel dies? Не забудьте добавить session.loop(0.1). Дополнительная информация по ссылке. Идея Thread /: on_process вдохновила меня написать драгоценный камень для моего собственного использования: https://github.com/da99/Chee/blob/master/lib/Chee.rb
  • Если последний вызов вашей рубиновой программы - SSH, вы можете exec ssh -tt [email protected] 'ruby numbers.rb'. Но, если вам все еще нужна интерактивность между User<->Ruby<->SSH, то предыдущая альтернатива является лучшей.
+0

Это такая полезная часть кода. Благодарим за создание и обмен. –

+0

Это не работает настолько, насколько это необходимо, чтобы иметь возможность полностью взаимодействовать с оболочкой. Например, для некоторых команд может потребоваться, чтобы vi (m) открывал и разрешал редактирование документа, и это не справлялось бы с этим. Хотя было бы неплохо, если Ruby справится с этим, я думаю, что много раз безопаснее просто писать сценарии оболочки в bash, если вам потребуется этот уровень интерактивности. –

Смежные вопросы