代码之家  ›  专栏  ›  技术社区  ›  raldi

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

  •  6
  • raldi  · 技术社区  · 16 年前

    我希望从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 回复  |  直到 16 年前
        1
  •  9
  •   brian d foy    16 年前

    来自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? .轮询文件句柄。如果有一个字符,读取它并重置计时器。如果没有字符,请重试。如果您已重试并通过了特定时间,请处理输入。

    看完这些角色后,由你决定如何处理它们。阅读单个字符的灵活性带来了额外的处理工作。

        2
  •  4
  •   Schwern    16 年前

    Term::ReadKey 我能为你做这件事。特别是设置ReadKey()模式来为您进行轮询。

    use Term::ReadKey;
    
    $| = 1;
    while( my $key = ReadKey(10) ) {
        print $key;
    }
    
        3
  •  1
  •   Adam Davis    16 年前

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

    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。

    -亚当

        4
  •  0
  •   Kyle    16 年前

    看见 How to change Open2 input buffering (基本上,你必须让另一个程序认为它在和tty对话。)

        5
  •  0
  •   brian d foy    16 年前

    您没有提到如何读取Perl脚本中的输入,但您可能想看看 getc 功能:

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