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:
- Make a backup copy of the file
- Open the file for read
- Open a new temporary file for write
- Go through the read file, and write it and any changes to the temp file
- When finished, close both files
- Delete the original file
- 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:
- The name of the file to be in-placed edited is taken from the first element of
@ARGV. In this case, that isc:/scripts/out.txt. The file is renamed to its existing name plus the value of$^I, ieout.txt.bk. - The file is read as usual by the diamond operator
<>, placing a line at a time into$_. - A new filehandle is opened, called
ARGVOUT, and no prizes for guessing it is opened on a file calledout.txt. The originalout.txtis renamed. - The
printprints automatically toARGVOUT, notSTDOUTas 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.