Recipe 7.9. Modifying a File in Place with -i Switch
Author: Tom Christiansen & Nathan Torkington
Date: 1999-07-02T01:36:32Z

#

| Chapter 7 File Access |

## 7.9. Modifying a File in Place with -i Switch

### Problem

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

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

### 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

### 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.7) to turn:

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

into:

    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

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 previously backed up version.

### See Also

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

7.8. Modifying a File in Place with Temporary File |  | 7.10. Modifying a File in Place Without a Temporary File