我的 perl 替换破折号模式清除了所有文件内容

My perl replace dash pattern wipes out all file contents

在我下面的代码中,我试图用相应数量的空格替换“---- ------”的模式。当我 运行 代码时,所有文件内容都被清除了。我不知道为什么。我在下面的示例文本中进行了替换。 我将不胜感激。

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Path;
use File::Copy;
use feature 'unicode_strings';
use utf8;    

my $IN;
my $dir;

opendir $dir, $Dirs[$mm] or die "opendir failed on $Dirs[$mm]: $! ($^E)";

while (my $file = readdir $dir) {        #reading input directory
    next if -d $file;

    if ($file =~ /Ranked/) {
        print "$file\n";
        open ($IN, "+> $Dirs[$mm]/$file") or die "open '$file': failed $! ($^E)";

        while (<$IN>) {
            s/---- ------/           /g;
            print "$_\n";
        }

        close $dir;
        exit;
    }
}

END
                          Ranked Rainfall: Jun
                          ********************
CHIPAT01     CHIPEP01     CHOMA001     ISOKA001     KABOMP01     KABWE001     KABWE002     KAFIRO01     KAFUE001     KALABO01     KAOMA001     KASAMA01     KASEMP01

Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl 1968 17.0 2003 13.2 2000 29.2 2004 3.1 1988 13.3 1988 2.8 ---- ------ 1967 2.8 1966 1.3 2009 2.3 1965 10.7 1968 11.9 1988 6.0 1983 5.8 2011 6.1 1966 14.0 2002 2.0 1965 9.4 1960 0.5 ---- ------ ---- ------ 1960 0.6 ---- ------ 2009 1.8 1952 0.8 1940 5.1 1974 4.6 1996 0.6 1997 4.5 ---- ------ 1966 2.3 1986 0.1 ---- ------ ---- ------ ---- ------ ---- ------ 1966 0.3 1936 0.3 1966 4.8 1960 3.3 2007 0.5 1988 4.0 ---- ------ Ave 0.5 Ave 0.1 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ Ave 0.2 1965 1.8 1999 0.3 2002 3.7 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1948 1.6 Ave 0.1 2003 3.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1971 1.0 ---- ------ 1955 3.3 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1978 0.9 ---- ------ 1976 2.5 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1961 0.5 ---- ------ 1975 1.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1946 0.5 ---- ------ 1978 1.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1967 0.5 ---- ------ 2011 1.4 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ Ave 0.4 ---- ------ 1960 1.3 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1964 0.3 ---- ------ 2009 1.0 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1996 0.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1969 0.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ Ave 0.5 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1958 0.5 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1979 0.3 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------

同时读取和写入同一个文件需要一些小心。在这里,您正在使用 +> 同时读取和写入 $file。但是,open 的文档警告说:

You can put a + in front of the > or < to indicate that you want both read and write access to the file; thus +< is almost always preferred for read/write updates--the +> mode would clobber the file first

相反,您应该写入一个临时文件。完成写入后,您可以用临时文件替换原始文件。要打开临时文件,可以使用 File::Temp module. To replace the original file with the new one, you can use move from the File::Copy 模块。您的代码已更正:

use File::Temp qw(tempfile);
use File::Copy;

while (my $file=readdir $dir) {
    next if -d "$dir/$file";
    if($file =~ /Ranked/){
        print "$file\n";

        my ($out_fh, $out_filename) = tempfile();
        open (my $IN, "<", "$Dirs[$mm]/$file") or die "open '$file': failed $! ($^E)";
        while( <$IN> ){
            s/---- ------/           /g;
            print $out_fh $_;
        }
        close $out_fh;
        copy($out_filename, "$Dirs[$mm]/$file");
    }
}

请注意,在 copy 之前关闭 $out_fh 很重要。


小提示:

  • next if -d $file 应该是 next if -d "$dir/$file".

  • 您应该在尽可能窄的范围内声明您的变量。这意味着您不应使用 my $IN; 开始您的脚本然后使用 open $IN, ...,您应该使用 open my $IN, ...my $diropendir.

    同样的事情

替代解决方案:

  • Perl 具有用于就地文件编辑的内置机制,但它更适合单行代码而不是完整脚本。如果需要,这由 -i command-line switch, but it can also be used 启用。

  • 一些 CPAN 包(例如 File::Inplace 可用于避免必须自己编写整个 tempfile/move 样板文件。