在Perl中,如何在输入到达时立即处理输入,而不是等待换行?

时间:2008-10-17 21:22:29

标签: perl

我想从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 个答案:

答案 0 :(得分:9)

来自perlfaq5:How can I read a single character from a file? From the keyboard?。您可能还想阅读How can I tell whether there's a character waiting on a filehandle?。轮询文件句柄。如果那里有一个字符,请阅读它并重置一个计时器。如果那里没有角色,请再试一次。如果您已重试并经过一段时间,请处理输入。

在您阅读完字符后,您可以决定如何处理这些字符。阅读单个字符的所有灵活性都是处理它们的额外工作。

答案 1 :(得分:4)

Term::ReadKey可以为您完成此操作。特别是设置ReadKey()模式为你进行轮询。

use Term::ReadKey;

$| = 1;
while( my $key = ReadKey(10) ) {
    print $key;
}

答案 2 :(得分:1)

如果每个角色之间有时间,您可能能够检测到暂停。

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程序来解析输入“命令行”并执行每个任务,根据需要吃stdout。

- 亚当

答案 3 :(得分:0)

您没有提到如何阅读Perl脚本中的输入,但您可能希望查看getc函数:

$|++; # set autoflush on output
while ($c = getc(STDIN)) {
    print $c;
}

答案 4 :(得分:0)

请参阅How to change Open2 input buffering。 (基本上,你必须让其他程序认为它与tty交谈。)