Перенаправление ввода-вывода с Ruby в GNU / Linux - PullRequest
0 голосов
/ 28 мая 2019

Итак, я написал небольшое приложение под названием cowspeak

Он выполняет различные работы в системе GNU / Linux. Но проблема в том, что при приеме входных данных используются каналы.

Я уже реализовал прием перенаправления ввода-вывода с этим кодом:

#!/usr/bin/ruby -w
require 'timeout'

STDIN.sync = STDOUT.sync = true
pipe = false

begin
    Timeout.timeout(0.000_000_000_001) do pipe = STDIN.gets end
rescue Timeout::Error
end

if pipe
    print pipe
    print pipe while pipe = STDIN.gets
end

Все хорошо.

Так что для echo -e "hello\nworld" | ruby cowspeak я получаю

hello
world

Но проблема в том, что он не работает с такими программами, как irb (да, мне не нужно использовать IRB с этой программой, но я хочу узнать, как она должна работать). Рабочий пример - драгоценный камень lolcat.

Так что для irb | ruby cowspeak я запускаю его вечно в цикле while (реализовано в цикле loop в cowspeak).

Lolcat отлично работает и в этом случае!

Кроме того, такие приложения, как cmatrix , не работают с моей программой, но они работают с lolcat.

Unix-программы, такие как cowsay (который написан на Perl), также плохо работают с конвейерами - такое же поведение, как cowspeak ...

В любом случае, я вижу вопрос, заданный ранее здесь: ruby ​​pipe, IO и перенаправление stderr

Но он не отвечает на мой вопрос должным образом.

Как я могу реализовать перенаправление ввода-вывода с Ruby и в целом, как гем lolcat действительно работает с трубами?

1 Ответ

1 голос
/ 29 мая 2019

Чтобы правильно прочитать все данные из канала, читайте блок за блоком без тайм-аутов, и убедитесь, что вы можете обрабатывать любые данные по мере их поступления:

#!/usr/bin/ruby -w

if STDIN.isatty
  STDERR.puts "You are not piping, but I will read from stdin anyways"
  STDERR.puts "because that is the canonical Unix behavior."
end

until STDIN.eof?
  STDOUT.write(STDIN.readpartial(4096))
end

Это исправляетдве проблемы с вашим опубликованным кодом (игнорирование всех других программ и комбинаций, о которых вы спрашиваете):

  1. Вы используете тайм-аут, поэтому программа завершится неудачно, если ввод будет медленным
  2. Вы читаете построчно, поэтому программа завершается сбоем, если ввод не основан на строках

echo, кажется, работает, потому что это встроенная оболочка и, следовательно, вероятно, будет работать до завершения rubyзагрузка, но это все еще до случая и планирования.Вот гонка, настроенная так, что echo проигрывает:

$ ( sleep 1; echo Hello ) | ./yourprogram
./yourprogram:9: warning: constant ::TimeoutError is deprecated

Вы также ждете полных строк, но irb выводит только подсказку без перевода строки, а cmatrix вообще не выводит перевод строки.,Это вызывает тайм-аут из-за вышеуказанной ошибки и в противном случае просто считывает память до тех пор, пока она не умрет:

$ while echo -n foo; do true; done | ./yourprogram
./yourprogram:9: warning: constant ::TimeoutError is deprecated

В приведенном выше предложении нет ни одной из этих проблем.

...