Как я могу прочитать стандартный вывод другой программы из программы Ruby построчно?

#ruby #io #stdout #stdin #popen

#ruby #io #стандартный вывод #popen

Вопрос:

У меня есть небольшая тестовая программа Ruby под названием «count», которая насчитывает 1 .. 50.

 #!/usr/bin/ruby
#count
for i in 1..50 do
 STDOUT.puts i
 sleep 1
end
  

Я хочу вызвать его из другой программы и прочитать выведенные числа построчно и вывести их из другой программы, строка за строкой.

Однако моя конструкция не работает:

 IO.popen("count","r ") {|f| puts f.readline}
  

Что я должен сделать, чтобы это заработало? Может быть, какая-то модификация в тестовой программе «count»?

Ответ №1:

Если у вас есть немного терпения (примерно на 50 секунд), вы увидите, что вы получаете одну строку вывода, и эта строка будет "1n" . У вас две проблемы:

  1. count использует буферизованный вывод. Это означает, что в вашем выходном буфере ничего не будет отображаться, stdin пока count выходной буфер не будет заполнен; учитывая небольшое количество байтов, которые вы печатаете, буфер не будет очищен до count завершения.
  2. Ваш popen блок ищет только одну строку.

Вы можете решить первую проблему, используя STDOUT.sync = true для отключения буферизации вывода в count :

 STDOUT.sync = true
for i in 1..50 do
  STDOUT.puts i
  sleep 1
end
  

Затем в вашем popen вы можете выполнять итерации по строкам с помощью each :

 IO.popen("count","r ") { |fp| fp.each { |line| puts line } }
  

Тогда вы должны отображать одну строку вывода каждую секунду.

Комментарии:

1. А что, если моя тестовая программа является обычной программой? Например, cURL или WGET, как я могу установить стандартный вывод.sync = true в этом случае? Или я должен написать программу-оболочку Ruby, которая вызывает обычную программу?

2. Вы пробовали с curl или wget ? Программы, которые предполагается использовать в конвейерах, как правило, ориентированы на конвейер и делают правильные вещи сами по себе. В противном случае вы ждете, пока буфер не заполнится.