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

Hello, I have a question about replacing text inside a whole bunch of files that reside in a directory.The filenames always end with .wra. The text to be replaced is found in the first line of each file (always the last 10 chars) and is to be replaced by the actual filename of the opened file (only the portion before the dot). I succeeded in opening all files and to get the filename out of the variable. But I don't know to: - find the text to be replaced and to put it into a variable - to replace the content of this variable with the actual filename. So you see, I'm a newbie and curious about learning more about perl. Would be very glad to find an answer. Thanks

Replies are listed 'Best First'.
Re: Replacing text inside lots of files
by Hena (Friar) on Oct 28, 2003 at 14:15 UTC
    To replace text (if you know the place) easiest way is to use 's///'. In this case (last 10 letters).
    # expecting that $file has file name. open (INF,"$file") or die "Unable to open \'$file\': $!"; open (OUTF,".temp_file") or die "Unable to create temp file: $!"; my $line=readline(INF); chomp($line); # if windows remember to $line=~s/\r$//o; # now change the last 10 characters from first line $line=~s/.{10}$/$file/; print "$line\n"; # this reads every line in file and prints it as is while (<INF>) { print OUTF "$_"; } rename (".temp_file","$file");


    Update
    Forgot to remove the '.wra' part from what is written in file. So to fix that add following between $line substitution and print.
    # remove all the character after last dot $line=~s/\.\w+$//o;
Re: Replacing text inside lots of files
by hanenkamp (Pilgrim) on Oct 28, 2003 at 14:09 UTC

    Well for text replacement, the obvious solution is regular expressions. You should see perlrequick, perlretut, and perlre for starters. Just as an example, if your first line contains the text REPLACEME, you could do something like:

    use English; # for $INPUT_LINE_NUMBER instead of $. # open files FILE and OUT while (<FILE>) { s/REPLACEME/$filename/ if $INPUT_LINE_NUMBER == 1; print OUT $_; } # close files

    You may also want to see English and perlvar for details on $. and the $INPUT_LINE_NUMBER variables (and cousins that I haven't mentioned).

Re: Replacing text inside lots of files
by delirium (Chaplain) on Oct 28, 2003 at 14:32 UTC
    perl -i~ -pe 'if($ARGV ne $l){$f=$l=$ARGV;$f=~s/\.wra//;substr($_,-11)=$f.$/;}' *

    OK, that looks crazy, I'm sure. Here's what's happening:

  • -i~ is doing an in-place edit of each file, and creating a backup extension of ~. That's in case there are mistakes in the code.
  • -pe is going to cycle through each line of each file, and print the contents of $_ at the end of the expression.
  • $ARGV is the name of the current file being looked at. The "if" statement checks to see when a new file is opened. When that happens, $_ is the first line of the new file.
  • $f is the filename without the .wra extension after the regular expression s/\.wra//.
  • The "substr($_,-11)=$f.$/" expression takes the last 11 characters of the first line (including the \n at the end) and replaces it with the contents of $f and another \n.
  • The asterisk at the end means each file in the current directory is going to be passed to the script. You may want to replace that with *.wra
      When I use this example for the problem, I get the error "Modification of a read-only value attempted at -e line 1, <> line 1." and the file is empty. Where do I make a mistake ? I used this example in a DOS-Box of WIN2k and also LINUX. Thanks for helping...
        You may have replaced $l (el) with $1 (one). $1 (one) is a reserved variable for Perl that catches parts of regular expression, and can't be assigned to directly. For example:

        ~/test$ perl -e '$1 = "blah"' Modification of a read-only value attempted at -e line 1.

        Whereas :

        ~/test$ perl -le '$var = "blah"; $var =~ /^(....)$/; print $1' blah
Re: Replacing text inside lots of files
by bradcathey (Prior) on Oct 28, 2003 at 14:29 UTC
    : platively new to real Perl programming, and I'm sure, as always, there are many ways, but one way:
    #!/usr/bin/perl -wT use strict; #my $filename is somehow parsed before this $filename =~ /^(\w+)\.\w+$/; my $replacewith = $1; open (FILE, "<$filename") || die ("Error: $!"); my $line = <FILE>; chomp $line; my $toreplace = substr($line,-10); close FILE; $line =~ s/$toreplace/$replacewith/;
    You did not mention whether the new file name will be 10 characters.

    Update
    Thanks hena for the elegant rewriting of the new file. Forgot that part!

      I would prefere the solution from Hena, because yours can fail if the last 10 chars repeat anywhere in the string, s/// takes the first match. s/.{10}$/$filename/ is safer here.
        Thanks Taulmarill. After reviewing hena's code, I see the more accurate regexp. But thanks to hena for that regexp--that's going in my arsenal of cool replacement regexps.