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