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

在Perl中,如何在输入到达时立即处理它,而不是等待换行符?,perl,Perl,我希望从Perl运行一个子命令(或将其导入Perl脚本),并让脚本立即处理命令的输出,而不是等待超时、换行或特定数量的块。例如,假设我想用方括号括住每个输入块。当我像这样运行脚本时: $ ( echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz) | my_script.pl 我希望输出是这样的,每行显示在前一行的五秒钟之后: [foo] [bar] [baz] 我该怎么做 这是可行的,但确实很难看: #! /usr/bin/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";
}

有更优雅的方法吗?

您没有提到如何在Perl脚本中读取输入,但您可能想看看函数:

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

看。(基本上,你必须让另一个程序认为它在和tty说话。)

如果每个字符之间有时间,你可能能够检测到暂停

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

并修改perl程序以解析输入“命令行”并执行每个任务,根据需要使用stdout

-来自perlfaq5的Adam:。你可能也想读书。轮询文件句柄。如果有一个字符,读取它并重置计时器。如果没有字符,请重试。如果您已重试并通过了特定时间,请处理输入

看完这些角色后,由你决定如何处理它们。阅读单个字符的所有灵活性都伴随着处理这些字符的额外工作。

可以为您做到这一点。特别是设置ReadKey()模式来为您进行轮询

use Term::ReadKey;

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

这不起作用——我已经更新了问题来解释原因。我的脚本没有输出任何方括号,它们必须来自您的脚本。如果看不到脚本的其余部分,很难说是什么导致了这种情况。使用精确的脚本,它一次打印一个字符,而不是一次打印一个块。为了举例说明,将打印行更改为打印“[$c]”;这似乎没有必要——我已经用一些有效的示例代码更新了问题,而没有诱使另一个程序认为它在与tty对话。我已经用一个有效的示例更新了问题,所以这绝对是可能的。现在我只想用正确的方式来做,你是说我的例子是最优雅的方式吗?或者有更好的方法吗?我是说,如果你想要所有的控制权,你必须自己做这项工作。当你想玩这个级别的东西时,没有魔法小马:)
use Term::ReadKey;

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