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 copy
ing it.
Small tips:
next if -d $file
should benext 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 doopen $IN, ...
, you should doopen my $IN, ...
. Same thing formy $dir
andopendir
.
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 wholetempfile
/move
boilerplate yourself.