В Perl, как мне обработать ввод, как только он прибудет, вместо ожидания новой строки? - PullRequest
6 голосов
/ 18 октября 2008

Я хотел бы запустить подкоманду из Perl (или передать ее в сценарий Perl) и заставить скрипт обрабатывать вывод команды немедленно, а не ждать тайм-аута, новой строки или определенного количества блоков. Например, допустим, я хочу заключить каждый фрагмент ввода в квадратные скобки. Когда я запускаю скрипт так:

$ ( echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz) | my_script.pl

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

[foo]
[bar]
[baz]

Как мне это сделать?

Это работает, но действительно ужасно:

#! /usr/bin/perl -w

use strict;
use Fcntl;

my $flags = '';
fcntl(STDIN, F_GETFL, $flags);
$flags |= O_NONBLOCK;
fcntl(STDIN, F_SETFL, $flags);

my $rin = '';
vec($rin,fileno(STDIN),1) = 1;
my $rout;

while (1) {
  select($rout=$rin, undef, undef, undef);
  last if eof();

  my $buffer = '';

  while (my $c = getc()) {
    $buffer .= $c;
  }

  print "[$buffer]\n";
}

Есть ли более элегантный способ сделать это?

Ответы [ 5 ]

9 голосов
/ 18 октября 2008

Из perlfaq5: Как я могу прочитать один символ из файла? С клавиатуры? . Вы, вероятно, также хотите прочитать Как я могу определить, есть ли символ, ожидающий в файловой ручке? Опрос файлового дескриптора. Если там есть персонаж, прочитайте его и сбросьте таймер. Если там нет персонажа, попробуйте еще раз. Если вы повторили попытку и прошли определенное время, обработайте ввод.

После того, как вы прочитали символы, вам решать, что с ними делать. При всей гибкости чтения отдельных символов появляется дополнительная работа с ними.

4 голосов
/ 19 октября 2008

Term :: ReadKey может сделать это для вас. В частности, установите режим ReadKey (), чтобы сделать опрос для вас.

use Term::ReadKey;

$| = 1;
while( my $key = ReadKey(10) ) {
    print $key;
}
1 голос
/ 18 октября 2008

Если между каждым символом есть время, вы можете обнаружить паузы.

Perl также вводит строки - если вы не используете getc, вы сможете добавлять новые строки в конец foo, bar и т. Д., И perl выдаст вам каждую строку.

Если вы не можете добавлять переводы строк и не можете зависеть от паузы, то что именно вы ожидаете от системы, чтобы сообщить Perl, что она запустила новую команду? Что касается perl, есть канал stdin, он получает данные из него, и в канале stdin нет ничего, что могло бы сказать вам, когда вы выполняете новую команду.

Вместо этого вы можете рассмотреть следующее:

$ echo "( echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz)" | my_script.pl

или

$ my_script.pl$ "echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz"

И измените вашу Perl-программу для анализа входной «командной строки» и выполнения каждой задачи, съедая стандартный вывод по мере необходимости.

-Adam

0 голосов
/ 18 октября 2008

См. Как изменить входную буферизацию Open2 . (По сути, вы должны заставить другую программу думать, что она разговаривает с tty.)

0 голосов
/ 18 октября 2008

Вы не упомянули, как вы читаете ввод в вашем скрипте Perl, но вы можете захотеть взглянуть на функцию getc:

$|++; # set autoflush on output
while ($c = getc(STDIN)) {
    print $c;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...