6

有一个文件:

:~$ 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

但是这个命令不会像预期的那样工作:第一个 <STDIN> 读取所有数据,而不是一行。如何禁用 <STDIN> 的缓冲?

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

3 回答 3

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")'

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

于 2012-09-10T12:29:58.913 回答
0

我最近不得不解析几个大约 6 GB 的日志文件。缓冲是一个问题,因为当我将 STDIN 分配给一个数组时,Perl 很乐意尝试将这 6 GB 读入内存……但是,我根本没有可用的系统资源来执行此操作。我想出了以下解决方法,它只需逐行读取文件,从而避免大量内存黑洞缓冲漩涡,否则会占用我所有的系统资源。

注意:这个脚本所做的就是将这个 6 GB 的文件分成几个较小的文件(其中的大小由每个输出文件中包含的行数决定)。有趣的是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 (输出文件的大小(即行数)

即使它不完全是您正在寻找的东西,我希望它会给您一些想法。:)

于 2013-01-24T10:28:54.347 回答
0

利用perl -ne

或者while(<STDIN>){do something with $_}

您可能不是指“缓冲”(通过 $|++ 禁用)-您错误地将所有 STDIN 放入 $_ 中,因为您忘记将其包装在一个循环中。

于 2022-02-12T12:07:19.323 回答