Table of Contents

Modifying a File with $^I

One of the most frequent Perl tasks is to open a file, make some changes and write it back to the original filename. You already have enough knowledge to do this. The steps would be:

  1. Make a backup copy of the file
  2. Open the file for read
  3. Open a new temporary file for write
  4. Go through the read file, and write it and any changes to the temp file
  5. When finished, close both files
  6. Delete the original file
  7. Rename the temp file to the original filename

If you have managed to get this far and assiduously work through the examples, the above will be child's play. Play if you want, but there is a Better Way.

Make sure you have data in c:\scripts\out.txt then run this:

@ARGV="c:/scripts/out.txt";

$^I=".bk";              # let the magic begin

while (<>) {
        tr/A-Z/a-z/;    # another new function sneaked in
        print;          # this goes to the temp filehandle, ARGVOUT, 
			# not STDOUT as usual, so don't mess with it !
}

So, what's happening? First, we load up @ARGV with the name of a file. It doesn't matter how @ARGV is loaded. We could have shifted the code from the command line.

The $^I is a special variable. You knew that just by looking at it. It's name is the Inplace Edit variable, and when it has a value the effects are:

  1. The name of the file to be in-placed edited is taken from the first element of @ARGV. In this case, that is c:/scripts/out.txt. The file is renamed to its existing name plus the value of $^I, ie out.txt.bk.
  2. The file is read as usual by the diamond operator <>, placing a line at a time into $_.
  3. A new filehandle is opened, called ARGVOUT, and no prizes for guessing it is opened on a file called out.txt. The original out.txt is renamed.
  4. The print prints automatically to ARGVOUT, not STDOUT as it would usually.

At the end of the operation you have neatly edited the file and made a backup. If you don't want a backup, assign a null string to $^I but don't go crying on any mailing lists if you lose data.

The usual method of in-place editing would involve just printing everything back where it came from until your regex finds whatever needs changing. You could of course slurp the whole file into memory and play with it there, which could be a lot easier but if you are dealing with files of more than a few megabytes this is probably not a feasible approach.

Now take a look at out.txt . Notice how all capital letters have been transliterated into lowercase. This is the tr operator at work, which is more efficient than regex for changing single characters. But that's only a small part of the tr function's value to the world. More later.

You should also have an out.txt.bk file. And finally, notice the way @ARGV has been created. You don't have to create it from the command line arguments -- it can be treated like an ordinary array, for that is what it is.