costas has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have written some code to open text files in a directory and perform simple search and replace commands. The code i used is simply...
my $line; open (FILEHANDLE, "<$new"); open (OUT, ">$new.bak") ; while ($line = <FILEHANDLE>) { $line =~ s/66/$goodrow->{'ClientID'}/g; $line =~ s/0906\s406\s2427/$SIMCard/g; print "$line<br>"; print (OUT $line); print (FILEHANDLE $line); } close FILEHANDLE; close OUT;
This works fine and is no problem but I hate the fact that I have to write to a new file and not write to the file i am reading from. I have tried to write code which allows me to open and write to the file itself, but amazingly i have been unsuccseful :-( the code I tried was along the lines of this...
my $line; open (FILEHANDLE, ">>$new"); while ($line = <FILEHANDLE>) { $line =~ s/66/$goodrow->{'ClientID'}/g; $line =~ s/0906\s406\s2427/$SIMCard/g; } close FILEHANDLE;
Of course it is obvious that this will not work but i cant seem to find the simple way of altering the text within this file once the regex is true. Can anyone give any tips as i havent found the answer elsewhere on the net.

Thanks (am i the only one who finds that they forget the simple stuff????)

Costas

Replies are listed 'Best First'.
Re: forgetting the simple stuff?
by zejames (Hermit) on Jun 26, 2002 at 09:02 UTC
    Hello

    This has been discussed several times on the Monastery. My favorite Way To Do It is merlyn's (and some others', of course :) :

    @ARGV = ($new); undef $/; $^I = ".bak"; while (<>) { s/66/$goodrow->{'ClientID'}/g; s/0906\s406\s2427/$SIMCard/g; print; }

    Your file will be modified "in place", and the old data will be saved in $new.bak
    All the dirty stuff is made for you by Perl ...
    HTH

    --
    zejames
Re: forgetting the simple stuff? (-i and $!)
by grinder (Bishop) on Jun 26, 2002 at 09:03 UTC
    It is possible to open a file for both reading and writing, but truth be told, it is hardly ever what you want. Basically, you can only write as many bytes as you read. If you try and read "bb" and replace it with "cccccc" you are going to clobber the four bytes that come after "bb" in the file. The bytes don't shift over and make room for you.

    The standard way of doing this is indeed to open a file with a different name, and then move it back over the old one when you have finished (assuming you consider that all has gone well). You can get perl to handle this automatically with the -i switch, otherwise, you can do it yourself.

    Another simple thing you are forgetting to do is not checking whether your opens are working correctly, or failing silently. Check the results of the $! variable.


    print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'
Re: forgetting the simple stuff?
by csotzing (Sexton) on Jun 26, 2002 at 10:53 UTC
    If you don't want to work with multiple files... can't you just store the data in an array while reading and substituting? Then after the work is done, reopen the file for writing out the array.
    # read and subst my $fh = new FileHandle($file,"<"); my @data = (); while (my $line = <$fh>) { $line =~ s/$expr1/$expr2/; push(@data,$line); } close($fh); # write new data $fh = new FileHandle($file,">"); foreach my $line (@data) { print $fh $line; } close($fh);

    print(map(lc(chr),split(6,qw/99672682673683684689632658645641610607/)));
Re: forgetting the simple stuff?
by blakem (Monsignor) on Jun 30, 2002 at 10:21 UTC
    Check out Tie::File by our very own Dominus. His writeup sounds like exactly what you're looking for. I believe your code would reduce to:
    tie @lines, 'Tie::File', $file or die "Couldn't open $file: $!"; for (@lines) { # actually modify the contents of the file s/66/$goodrow->{ClientID}/g; s/0906\s406\s2427/$SIMCard/g; } untie @lines;

    -Blake