读取整个文件然后在内部编辑时打印?

d5e*_*5e5 4 perl inplace-editing

大多数就地编辑的例子都是单行,它们遍历一个或多个文件,一次读取和打印一行.

我找不到任何将整个文件读入数组,根据需要修改数组,然后在使用^ I开关进行就地编辑时打印数组的示例.当我尝试从钻石操作员读取整个文件,编辑内容并打印整个内容时,我发现打印转到STDOUT而不是ARGVOUT并且ARGVOUT已关闭.我可以打开相同的文件输出然后打印到它,但我不确定我理解为什么这是必要的.这是一个例子:

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;

my $filename = 'test.txt';

push @ARGV, $filename;

$^I = ".bk";

my @file = <>; #Read all records into array
chomp @file;
push @file, qw(add a few more lines);

print join "\n", @file; #This prints to STDOUT, and ARGVOUT is closed. Why?
Run Code Online (Sandbox Code Playgroud)

运行上述操作会按预期方式备份test.txt文件,但将编辑后的test.txt保留为空,将编辑后的内容打印到STDOUT.

mob*_*mob 6

perlrun.

-i调用该开关时,perl使用ARGVOUT默认文件句柄而不是启动程序STDOUT.如果有多个输入文件,则每次<><ARGV>readline(ARGV)操作完成一个输入文件时,它会关闭ARGVOUT并重新打开它以写入下一个输出文件名.

一旦所有输入<>都耗尽(当没有更多文件要处理时),perl将关闭ARGVOUTSTDOUT再次恢复为默认文件句柄.或者如perlrun

#!/usr/bin/perl -pi.orig
s/foo/bar/;
Run Code Online (Sandbox Code Playgroud)

相当于

#!/usr/bin/perl
$extension = '.orig';
LINE: while (<>) {
    if ($ARGV ne $oldargv) {
        if ($extension !~ /\*/) {
            $backup = $ARGV . $extension;
        }
        else {
            ($backup = $extension) =~ s/\*/$ARGV/g;
        }
        rename($ARGV, $backup);
        open(ARGVOUT, ">$ARGV");
        select(ARGVOUT);
        $oldargv = $ARGV;
    }
    s/foo/bar/;
}
continue {
    print;  # this prints to original filename
}
select(STDOUT);
Run Code Online (Sandbox Code Playgroud)

一旦你说出my @file = <>并消耗了所有输入,Perl就会将文件句柄关闭到备份文件并开始STDOUT再次指向输出.


我认为,解决方法是调用<>标量上下文并eof(ARGV)在每行后检查.何时eof(ARGV)=1,您已经阅读了该文件中的最后一行,并且在<>再次拨打电话之前有一次机会打印:

my @file = ();
while (<>) {
    push @file, $_;
    if (eof(ARGV)) {
        # done reading current file
        @processed_file = &do_something_with(@file);
        # last chance to print before ARGVOUT gets reset
        print @processed_file;
        @file = ();
    }
}
Run Code Online (Sandbox Code Playgroud)