#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"
. У вас две проблемы:
count
использует буферизованный вывод. Это означает, что в вашем выходном буфере ничего не будет отображаться,stdin
покаcount
выходной буфер не будет заполнен; учитывая небольшое количество байтов, которые вы печатаете, буфер не будет очищен доcount
завершения.- Ваш
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
? Программы, которые предполагается использовать в конвейерах, как правило, ориентированы на конвейер и делают правильные вещи сами по себе. В противном случае вы ждете, пока буфер не заполнится.