Home > Mobile >  My perl replace dash pattern wipes out all file contents
My perl replace dash pattern wipes out all file contents

Time:12-14

In my code below I am trying to replace the pattern of "---- ------" with the corresponding number of spaces. When I run the code, all the file contents are wiped out. I cannot figure out why. I have the sample text below where the replacements are to be done. I would appreciate assistance.

#!/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 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------

CodePudding user response:

Reading and writing to the same file at the same time requires some care. Here, you are using > to read and write to $file at the same time. However, the documentation of open warns that:

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

Instead, you should write to a temporary file. Once you're done writing, you can replace the original file with the temporary one. To open a temporary file, you can use the File::Temp module. To replace the original file with the new one, you can use move from the File::Copy module. Your code corrected:

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");
    }
}

Note that it's important to close $out_fh before copying it.


Small tips:

  • next if -d $file should be next if -d "$dir/$file".

  • You should declare your variables in the narrowest scope possible. This means that instead of starting your script with my $IN; and later do open $IN, ..., you should do open my $IN, .... Same thing for my $dir and opendir.


Alternative solutions:

  • Perl has a built-in mechanism for in-place file editing, but it's more suitable for one-liners than for full scripts. This is enabled by the -i command-line switch, but it can also be used outside of one-liners if needed.

  • Some CPAN packages (such as File::Inplace can be used to avoid having to write the whole tempfile/move boilerplate yourself.

  •  Tags:  
  • perl
  • Related