Many of you are probably aware of the pattern of opening a temporary file, reading from the original file and writing the modified contents to the temporary file, and then renameing the temporary file over the original file, which is often an atomic operation (depending on OS & FS). I recently wrote a module to encapsulate this behavior, and here is one of three interfaces that are available in File::Replace. There are several options to configure the behavior, including the ability to specify PerlIO layers, what happens if the file doesn't exist yet, etc.

use File::Replace 'replace2'; my ($infh,$outfh) = replace2($filename); while (<$infh>) { # write whatever you like to $outfh here print $outfh "X: $_"; } close $infh; # closing both handles will close $outfh; # trigger the replace

Since I hope this is something that you might find useful, I would be happy about any feedback you might have!

To give a practical example, here is an update of my code from this node. As you can see I was able to get rid of eight lines of fairly complicated code, while keeping the main loop entirely unchanged. The module also adds some more robustness, as it incorporates a few more checks on whether operations were successful or not.

#!/usr/bin/env perl use warnings; use strict; use File::Replace 'replace2'; my $filename = "/tmp/test.html"; my @to_insert = ( '<p>Hello,', 'World! It is '.gmtime(time).' UTC</p>' ); my ($ifh,$tfh) = replace2($filename); my $found; while (<$ifh>) { print $tfh $_; if (/<!--\s*INSERT\s+HERE\s*-->/i) { $found=1; print $tfh "$_\n" for @to_insert; } } close $ifh; close $tfh; die "Marker not found" unless $found;