Modifying a File in Place with the -i Switch (Perl Cookbook, 2nd Edition)

## 7.16. Modifying a File in Place with the -i Switch

### 7.16.1. Problem

You need to modify a file in place from the command line, and you're too lazy[15] for the file manipulation of Recipe 7.15.

> [15]Lazy-as-virtue, not lazy-as-sin.

### 7.16.2. Solution

Use the -i and -p switches to Perl. Write your program on the command line:

>     % perl -i.orig -p -e 'FILTER COMMAND' file1 file2 file3 ...

or use the switches in programs:

>     #!/usr/bin/perl -i.orig -p
>     # filter commands go here

### 7.16.3. Discussion

The -i command-line switch modifies each file in place. It creates a temporary file as in the previous recipe, but Perl takes care of the tedious file manipulation for you. Use it with -p (explained in Recipe 7.14) to turn:

>     while (<>) {
>         if ($ARGV ne $oldargv) {           # are we at the next file?
>             rename($ARGV, $ARGV . ".orig");
>             open(ARGVOUT, ">", $ARGV);     # plus error check
>             select(ARGVOUT);
>             $oldargv = $ARGV;
>         }
>         s/DATE/localtime/e;
>     }
>     continue{
>         print;
>     }
>     select (STDOUT);                      # restore default output

into:

>     % perl -pi.orig -e 's/DATE/localtime/e'

The -i switch takes care of making a backup (say `-i` instead of `-i.orig` to discard the original file contents instead of backing them up), and -p makes Perl loop over filenames given on the command line (or `STDIN` if no files were given).

The preceding one-liner would turn a file containing the following:

>     Dear Sir/Madam/Ravenous Beast,
>         As of DATE, our records show your account
>     is overdue.  Please settle by the end of the month.
>     Yours in cheerful usury,
>         --A. Moneylender

into:

>     Dear Sir/Madam/Ravenous Beast,
>         As of Sat Apr 25 12:28:33 1998, our records show your account
>     is overdue.  Please settle by the end of the month.
>     Yours in cheerful usury,
>         --A. Moneylender

This switch makes in-place translators a lot easier to write and to read. For instance, this changes isolated instances of "`hisvar`" to "`hervar`" in all C, C++, and yacc files:

>     % perl -i.old -pe 's{\bhisvar\b}{hervar}g' *.[Cchy]

Turn on and off the -i behavior with the special variable `$^I`. Set `@ARGV`, and then use `<>` as you would with -i on the command line:

>     # set up to iterate over the *.c files in the current directory,
>     # editing in place and saving the old file with a .orig extension
>     local $^I   = ".orig";              # emulate  -i.orig
>     local @ARGV = glob("*.c");          # initialize list of files
>     while (<>) {
>         if ($. =  = 1) {
>             print "This line should appear at the top of each file\n";
>         }
>         s/\b(p)earl\b/${1}erl/ig;       # Correct typos, preserving case
>         print;
>     } continue {close ARGV if eof}

Beware that creating a backup file under a particular name when that name already exists clobbers the version previously backed up.

### 7.16.4. See Also

perlrun(1), and the "Switches" section of Chapter 19 of Programming Perl; the `$^I` and `$`. variables in perlvar(1), and in Chapter 28 of Programming Perl; the `.`. operator in the "Range Operator" sections of perlop(1) and Chapter 3 of Programming Perl

Copyright © 2003 O'Reilly & Associates. All rights reserved.