Perl,禁用缓冲输入

时间:2012-09-10 12:15:40

标签: perl buffering

有一个文件:

:~$ cat fff
qwerty
asdf
qwerty
zxcvb

有一个脚本:

:~$ cat 1.pl
#!/usr/bin/perl
print <STDIN>

该命令按预期工作:

:~$ cat fff | perl -e 'system("./1.pl")'
qwerty
asdf
qwerty
zxcvb

但是这个命令不会按预期工作:第一个&lt; STDIN&gt;读取所有数据,而不是单行。如何禁用&lt; STDIN&gt;?

的缓冲
:~$ cat fff | perl -e '$_ = <STDIN>; system("./1.pl")'
:~$

2 个答案:

答案 0 :(得分:6)

此处有两个Perl流程 - 第一个指定$_ = <STDIN>并调用system,第二个处理print <STDIN>

虽然第一个进程只将流的第一行读入$_,但在幕后Perl已用数据填充其缓冲区并将流留空

这是为了什么目的?想到你要做的唯一方法是在第一个过程中将文件的所有读入一个数组,然后删除第一行并将其余部分通过管道发送到第二行脚本

所有这些似乎都是不必要的,如果你能描述潜在的问题,我相信还有更好的方法

<强>更新

由于你说你知道缓冲问题,所以这样做的方法是使用sysread,它将从较低级别的管道读取并避免缓冲

这样的东西会起作用

cat fff | perl -e 'while (sysread(STDIN, $c, 1)) {$_ .= $c; last if $c eq "\n"} system("./1.pl")'

但我不喜欢推荐它,因为你正在做的事似乎非常错误,我希望你能解释你的真正目标

答案 1 :(得分:0)

我最近不得不解析几个大约6千兆字节的日志文件。缓冲是一个问题,因为当我将STDIN分配给一个数组时,Perl很乐意尝试将这些6千兆字节读入内存......但是,我根本没有可用的系统资源来做到这一点。我提出了以下解决方法,它只是逐行读取文件,因此避免了大量的内存黑洞缓冲涡流,否则会占用我的所有系统资源。

注意:所有这个脚本都将6千兆字节的文件拆分成几个较小的文件(其大小由每个输出文件中包含的行数决定)。有趣的是while循环以及从日志文件到变量的单行分配。循环将遍历读取单行的整个文件,对其执行某些操作,然后重复。结果,没有大规模的缓冲...我保持整个脚本完整只是为了展示一个有效的例子......

#!/usr/bin/perl -w
BEGIN{$ENV{'POSIXLY_CORRECT'} = 1;}
use v5.14;
use Getopt::Long qw(:config no_ignore_case);

my $input = '';
my $output = '';
my $lines = 0;
GetOptions('i=s' => \$input, 'o=s' => \$output, 'l=i' => \$lines);

open FI, '<', $input;

my $count = 0;
my $count_file = 1;
while($count < $lines){
    my $line = <FI>; #assign a single line of input to a variable
    last unless defined($line);
    open FO, '>>', "$output\_$count_file\.log";
    print FO $line;
    $count++;
    if($count == $lines){
        $count=0;
        $count_file++;
    }
}
print " done\n";

在命令行上调用脚本,如:

(脚本名称)-i(输入文件)-o(输出文件)-l(输出文件的大小(即行数)

即使它不是你想要的,我希望它会给你一些想法。 :)