【问题标题】:Read unbuffered data from pipe in Perl在 Perl 中从管道中读取无缓冲数据
【发布时间】:2012-03-27 01:19:35
【问题描述】:

我正在尝试从 Perl 的管道中读取未缓冲的数据。例如在下面的程序中:

open FILE,"-|","iostat -dx 10 5";
$old=select FILE;
$|=1;
select $old;
$|=1;

foreach $i (<FILE>) {
  print "GOT: $i\n";
}

iostat 每 10 秒(五次)吐出数据。你会期望这个程序做同样的事情。但是,它似乎会挂起 50 秒(即 10x5),之后它会吐出所有数据。

我怎样才能在不一直等待 EOF 的情况下返回任何可用的数据(以无缓冲的方式)?

附:我在 Windows 下看到过​​很多关于此的引用 - 我正在 Linux 下执行此操作。

【问题讨论】:

  • 您应该使用while 而不是foreach。而且你的输出缓冲是无关紧要的,因为它是一个输入句柄而不是一个输出句柄。
  • 使用while和foreach有什么区别?
  • @alertjean:在foreach my $i (&lt;FILE&gt;) { ... } 中,文件读取是在列表上下文中完成的,即在foreach 循环中处理行之前读取整个文件。在while (my $i = &lt;FILE&gt;) { ... } 中,读取是在标量上下文中完成的,即读取每一行,然后在 while 块中处理,然后再读取下一行。

标签: linux perl perl-io


【解决方案1】:

如果可以在 Perl 脚本中等待而不是在 linux 命令上等待,这应该可以。 在命令执行完成之前,我认为 Linux 不会将控制权交还给 Perl 脚本。

#!/usr/bin/perl -w
my $j=0;
while($j!=5)
{
    open FILE,"-|","iostat -dx 10 1";
    $old=select FILE;
    $|=1;
    select $old;
    $|=1;

    foreach $i (<FILE>)
    {
        print "GOT: $i";
    }
    $j++;
    sleep(5);
}

【讨论】:

  • 设置 $| 只会影响输出缓冲。 你不能以这种方式影响其他程序的输出缓冲。加上奇怪的打开而不是 open(PIPEHANDLE, "iostat -dx 10 1 |") || die "can't start pipe"; 是什么?我永远记不起 "|-""-|" 我自己。无论如何,如果iostat 程序没有通过管道刷新它的缓冲区,你必须求助于 ptys,这确实很麻烦,但不可避免。
【解决方案2】:

我有以下代码为我工作

#!/usr/bin/perl
use strict;
use warnings;
open FILE,"-|","iostat -dx 10 5";

while (my $old=<FILE>)
{
  print "GOT: $old\n";
}

【讨论】:

  • 为什么不open(FILE, "iostat -dx 10 5 |")
  • @tchist 因为open PIPE, '-|', 'iostat', '-dx', 10, 5 要么死$!
【解决方案3】:
#!/usr/bin/env perl

use strict;
use warnings;



open(PIPE, "iostat -dx 10 1 |")       || die "couldn't start pipe: $!";

while (my $line = <PIPE>) {
    print "Got line number $. from pipe: $line";
}

close(PIPE)                           || die "couldn't close pipe: $! $?";

【讨论】:

    【解决方案4】:

    到目前为止,关于取消缓冲的解决方案对我不起作用(Windows ActiveState Perl 5.10)。

    根据http://perldoc.perl.org/PerlIO.html,“要获得无缓冲的流,请在开放调用中指定无缓冲的层(例如 :unix ):”。

    所以

    open(PIPE, '-|:unix', 'iostat -dx 10 1') or die "couldn't start pipe: $!";
    
    while (my $line = <PIPE>) {
        print "Got $line";
    }
    
    close(PIPE);
    

    这在我的情况下有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多