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

Very simple - but very stuck. I want to open a file, read it's contents line by line, perform a regex on each line, make a substitution if necessary, write it to the file, then close the file.
#!/usr/bin/perl -w use strict; open(FOO, "+< $foo") or die "Can't open $foo: $!"; while (<FOO>) { chomp; my $line = $_; $line = s/hello/goodbye/gi; } close FOO;
The regex works, but it doesn't output anything to the file I'm opening. I'm guessing that I need a if statement by the regex and a print statement.....anyone?

Replies are listed 'Best First'.
Re: Editing Contents of a File
by pbeckingham (Parson) on Jun 21, 2004 at 13:58 UTC

    The simplest way is a one-liner:

    perl -i.bak -pe 's/hello/goodbye/gi' file1 file2 ...
    You are reading the file and modifying an in-memory string, but not attempting to write that string back out. I would do this:
    use Fcntl qw(:seek); open (FOO, "+<$foo") or die "Can't open $foo: $!"; my $slurp = join '', <FOO>; $slurp =~ s/hello/goodbye/sgi; seek FOO, 0, SEEK_SET; print FOO $slurp; truncate FOO, tell FOO; close FOO;
    Update: Added the truncate call for cases where the modified file contents are shorter than the original. Oops.

Re: Editing Contents of a File
by ColtsFoot (Chaplain) on Jun 21, 2004 at 13:54 UTC
    You don't appear to be writiing anything to the output file.
    May I suggest the following
    #!/usr/bin/perl -w use strict; open INPUT, 'your_input_fiel.txt'; open OUTPUT '>your_output_file.txt'; while (my $line = <INPUT>) { chomp $line; $line =~ s/hello/goodbye/gi' print <OUTPUT> $line; } close INPUT; close OUTPUT;
    Hope this helps
Re: Editing Contents of a File
by borisz (Canon) on Jun 21, 2004 at 13:57 UTC
    or do all in one shot:
    perl -pe 's/hello/goodbye/g' <infile >outfile
    Boris
Re: Editing Contents of a File
by hmerrill (Friar) on Jun 21, 2004 at 14:05 UTC
    The problem is you aren't 'print'ing to the file anywhere.

    The Perl Cookbook p.243-244 recipe 7.10 shows "Modifying a File in Place with -i Switch" - you basically open the file with "+<", read the whole file into an array, update the array, then rewrite the file and truncate it to its current seek pointer:

    open(FH, "+< FILE") or die "Opening: $!"; @ARRAY = <FH>; # change ARRAY here seek(FH,0,0) or die "Seeking: $!"; print FH @ARRAY or die "Printing: $!"; truncate(FH,tell(FH)) or die "Truncating: $!"; close(FH) or die "Closing: $!";
    If you don't mind using a temporary file, there's another recipe in the same section.

    HTH.

      I'm such a dolt! I posted this message and then looked in my Cookbook and BOOM there it was! The Cookbook's recipe 7.10 is great but I think I'm going to go down the route of create a temp file. Thanks for the insight this was very helpful and this is the reason that I keep coming back to the Monks when I'm stuck.
Re: Editing Contents of a File
by eserte (Deacon) on Jun 21, 2004 at 14:46 UTC
    If you're lazy, then try Tie::File:
    #!/usr/bin/perl -w use strict; use Tie::File; tie my @a, "Tie::File", "/tmp/foo" or die $!; for (@a) { s/hello/goodbye/gi; }
Re: Editing Contents of a File
by blue_cowdawg (Monsignor) on Jun 21, 2004 at 15:08 UTC

        I want to open a file, read it's contents line by line, perform a regex on each line, make a substitution if necessary, write it to the file, then close the file.

    consider this bit of code:

    use Tie::File; use strict; my @ry=(); # I'm not sure where $foo came from in your OP... tie @ry,"Tie::File","$foo" or die "$foo -- $!"; $_ =~s/hello/goodbye/gi foreach @ry; untie @ry;