(There are exceptions in special circumstances. Replacing a sequence of
bytes with another sequence of the same length, for example. Another is
using the $DB_RECNO
array bindings as documented in
the DB_File manpage. Yet another is manipulating files with all lines the same length.)
The general solution is to create a temporary copy of the text file with the changes you want, then copy that over the original.
$old = $file; $new = "$file.tmp.$$"; $bak = "$file.bak";
open(OLD, "< $old") or die "can't open $old: $!"; open(NEW, "> $new") or die "can't open $new: $!";
# Correct typos, preserving case while (<OLD>) { s/\b(p)earl\b/${1}erl/i; (print NEW $_) or die "can't write to $new: $!"; }
close(OLD) or die "can't close $old: $!"; close(NEW) or die "can't close $new: $!";
rename($old, $bak) or die "can't rename $old to $bak: $!"; rename($new, $old) or die "can't rename $new to $old: $!";
Perl can do this sort of thing for you automatically with the -i
command-line switch or the closely-related $^I
variable (see
-i and $^I for more details). Note that -i
may require a suffix on some non-Unix systems; see the platform-specific
documentation that came with your port.
# Renumber a series of tests from the command line perl -pi -e 's/(^\s+test\s+)\d+/ $1 . ++$count /e' t/op/taint.t
# form a script local($^I, @ARGV) = ('.bak', glob("*.c")); while (<>) { if ($. == 1) { print "This line should appear at the top of each file\n"; } s/\b(p)earl\b/${1}erl/i; # Correct typos, preserving case print; close ARGV if eof; # Reset $. }
If you need to seek to an arbitrary line of a file that changes infrequently, you could build up an index of byte positions of where the line ends are in the file. If the file is large, an index of every tenth or hundredth line end would allow you to seek and read fairly efficiently. If the file is sorted, try the look.pl library (part of the standard perl distribution).