1

I have done this so far but its still not working.

open (GOOD_FILE,"<$pre.XXX.XXX$post") or die "Cannot open XXX";

# temporarily undefine the input line separator to read the entire file at once:
my $text = do { local $/; <GOOD_FILE> };
close GOOD_FILE or die $!;
#File name to replace XXXX.XXXXX.XXXX.XXXX.CCCC where last CCCC can be     anything 
$text =~ s/^(.*\n)?XXXX\.XXXX\.XXXX\.[^\n]*/$1myname/s;

open (GOOD_FILE,"<$pre.XXXX.XXXX$post") or die "Cannot open XXXX";
print GOOD_FILE $text;
close GOOD_FILE or die $!;

The input file looks like this:

I am tester testing
I am still learning.
XXXX.XXXX.XXXX.XXXX.CCCC
I am tester.
XXXX.XXXX.XXXX.XXXX.PPPP

It should produce this output:

I am tester testing
I am still learning.
XXXX.XXXX.XXXX.XXXX.CCCC
I am tester.
myname.

But I am getting empty file.

Thank you guys, I was able to solve the problem using the variable in what to replace I just regex as variable and it worked fine.

mysteriousboy
  • 159
  • 1
  • 7
  • 20

1 Answers1

3

When you open a file for writing with the > mode, it's automatically truncated to zero length.

It is possible to open a file for both reading and writing simultaneously, without truncating it, using the +< mode, but actually modifying a file like that is a bit tricky since it requires seeking.

Instead, there are two simple ways to accomplish what you want. If you know the file will always be relatively short, you can just read it into memory, modify it and write it back:

my $filename = 'filename.txt';

open my $in, '<', $filename or die $!;
# temporarily undefine the input line separator to read the entire file at once:
my $text = do { local $/; <$in> };
close $in or die $!;

$text =~ s/^(.*\n)?MY\.FILE\.NAME\.[^\n]*/$1myname/s;

open my $out, '>', $filename or die $!;
print $out $text;
close $out or die $!;

The other solution, for large files, is to write the output to a temporary file and then move the temporary file over the original one when you're done. This is more or less what perl's -i switch does, and it allows you to edit arbitrarily long files line by line (as long as you have enough disk space to store the copy, anyway). Unfortunately, in your case matching the last occurrence of a particular string in the file gets a bit tricky using this method.

(I suppose you could use File::ReadBackwards, but unfortunately there's no File::WriteBackwards module to go with it (and it would be quite difficult to write one due to limitations of the OS file I/O interface), so you'd basically have to write the output lines to the temporary file in reverse order and then do a second pass to copy them back into the original file in the correct order. It should be possible, but kind of complicated.)

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • Please see the updated code and if you could help me that would be great. – mysteriousboy Dec 24 '12 at 21:22
  • When writing, you need to open the file in `>` mode, not `<`. Also, it looks like your regexp has an extra `\.` after `CAM` even though no period appears at that position in your example input. Finally, I'd very strongly suggest starting your script with `use strict;` and `use warnings;` and fixing any complaints they generate; I'm pretty sure having warnings enabled would've told you about the first mistake. – Ilmari Karonen Dec 24 '12 at 21:22
  • I have used use strick and use warnings and corrected write mode to write file but still its not writing. here is my replace $text =~ s/^(.*\n)?NSHT\.FIN\.CAM0000\.ESCR\.INPUT01\.*/$1myname/s; – mysteriousboy Dec 24 '12 at 21:46
  • The file to replace is NSH[T][P].FIN.CAM0000.ESCR.INPUT01.121210 where date can be anything that is after last dot. Also there may be other string after the file name but that will be after space in same like so I removed \n you originally suggester. Thanks for your help. – mysteriousboy Dec 24 '12 at 21:48
  • OK, try writing the output to a _different_ file than the one you used for input. If the new file gets written but looks identical to the original, the problem is in your regexp. If it doesn't get written, the problem is in your file I/O. – Ilmari Karonen Dec 24 '12 at 21:52
  • Yes I created the new file and its identical to original file. Is there any simple regex all I want is if the string is NSHT.FIN.CAM0000.ESCR.INPUT01.* or NSHP.FIN.CAM0000.ESCR.INPUT01.* I want to replce with my variable for last occurance the file will have multiple NSHT.FIN.CAM0000.ESCR.INPUT01.* – mysteriousboy Dec 24 '12 at 21:58
  • Try `NSH[TP]\.FIN\.CAM0000\.ESCR\.INPUT01\.\d+` (and take a look at [perlretut](http://perldoc.perl.org/perlretut.html)). – Ilmari Karonen Dec 24 '12 at 22:00
  • Thank you very much I tested the regex you gave still not working let me do some study and I will check if I am able to solve it. Thanks for the help. – mysteriousboy Dec 24 '12 at 22:11
  • I was able to solve it thanks, I use variable as regex it it worked. – mysteriousboy Dec 28 '12 at 17:00