Захват вывода интерактивной внешней команды, запускаемой изнутри Ruby - PullRequest
0 голосов
/ 26 сентября 2018

Я искал способ запустить интерактивную команду (например, ssh) и записать ее вывод.Это звучит просто, но, насколько я понимаю, мой вариант использования немного отличается от многих результатов Google и S / O.

Чтобы быть понятным, под интерактивным я имею в виду пользователя, который запускает my_ruby_script.rb изтерминал должен иметь возможность

  1. вводить (stdin) команду работающей интерактивной системы (например, вводить ls через ssh туннель)
  2. считывать из (stdout / stderr) запущенная интерактивная системная команда (опять же, например, просмотр результата ls в туннеле ssh)

Кроме того, я хотел бы прочитатьвывод системной команды (ssh), поэтому я могу, например, проверить наличие ошибок внутри моего скрипта Ruby.Самое близкое, что я получил, это просто tee вывод в другой файл.

system('ssh username@ssh_server |& tee ssh_log.txt')

Это не идеально, так как

  1. Это требует сохранения в / чтения изотдельный файл
  2. Требуется более сложный системный вызов, который может быть или не быть переносимым

Насколько я понимаю, большинство решений в сети (backticks, Open3.*, PTY.spawn() и т. д.) перенаправьте stdin / stdout из интерфейса терминала в программу ruby.То, что я ищу - это оставить stdin в покое и использовать stdout для моего сценария на Ruby.У кого-нибудь есть идеи?

Я должен отметить, что system('ssh username@ssh_server') делает именно то, что я хочу, мне просто нужно иметь возможность прочитать вывод.Кроме того, я бы предпочел не использовать net-ssh и другие библиотеки, не относящиеся к stdlib.

Research:

  1. Это, пожалуй, самая полная страница, описывающая выполнение команд в Ruby ( Когда использовать каждый метод запуска подпроцесса в Ruby и связанные сообщения в блоге).
  2. У этих людей (как мне кажется) моя точно такая же проблема:
  3. Эти люди используют ssh через Ruby, но их сценарии не являются "интерактивными"

Я очень ценю любые идеи, которые вы можете предоставить.

1 Ответ

0 голосов
/ 27 сентября 2018

Я нашел свой ответ!Большое спасибо @Kimmo Lehto за идею IO.copy_stream(), которая привела к моему окончательному решению.В основном, мы используем PTY.spawn(cmd){|stdin, stdout, pid| ...}, чтобы получить небуферизованные потоки для stdin и stdout.

Затем мы копируем stdin скрипта в stdin команды с IO.copy_stream($stdin.raw!, $stdin) (не забудьтеустановить $stdin.cooked! впоследствии).

Я не мог понять, как использовать copy_stream в команде stdout дважды (сначала для скрипта stdout, затем для буфера, например, io = StringIO.new) поэтому мне приходилось вручную читать каждый символ примерно так: stdout.readchar(|c| print c; io.write c).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...