|Perl: the Markov chain saw|
perl -i -pe ... with eof() testingby Anonyrnous Monk (Hermit)
|on Feb 08, 2011 at 18:38 UTC||Need Help??|
Anonyrnous Monk has asked for the
wisdom of the Perl Monks concerning the following question:
Occasionally, I get the opportunity to impress collegues with an elegant one-liner in our beloved language. This time, though, the advocacy didn't work out too well so far... ;)
The task is to go through a number of config files and fix up a certain entry if it exists, or else (if the entry doesn't exist) append it to one of the files (last file processed is fine, but so is any other).
It's important the entry does not exist in multiple files as a result of the fixing, and it's preferable to leave it where it was, in case it was found. It can be assumed the entry exists exactly only one or zero times in the original input files. Also, files should be edited in place.
Case 1 — entry "opt=foo" already exists, fix it with s/opt=.*/opt=bar/:
Case 2 — entry doesn't exist, append "opt=bar" to last file:
The first idea was to use an END block to conditionally output the last line
This doesn't work, however, because the print goes to stdout, instead of the file being edited in-place. (print ARGV ... doesn't work either; $! says "Bad file descriptor", presumably because ARGV is already closed at that point.)
So, next idea was to use eof to be able to move the test into the the loop implied by -p. However, while this in principle works fine with eof (which is true at the end of every file), it doesn't work with eof(), which should be true only once after all files have been processed — which is what would really be needed to avoid multiple insertions of the entry in question.
Interestingly, not even case 1 (where the eof() wouldn't really be needed) works. Here, the last line ("line3") is also being written to stdout instead of to the file, in case eof() is being tested...
Can anyone explain what's going on here? Is this behavior documented somewhere? (Of course, there are many more or less clumsy ways to solve this another way, but I'm primarily interested in why this approach doesn't do what I'd expected.)
Update: Solution: in cases like these, replace eof() with !@ARGV && eof, which doesn't have the undesirable side effect...