Incorrect command-line perl error value in $?

I am using command-line perl to perform a inplace substitution in a file. This is the code: (note the root perm with sudo)

sudo perl -i -pe "s/foo/bar/" config.txt

If this succeeds, 'echo $?' return 0. Now I make the file un-writable even for root using chattr like this:

sudo chattr +i config.txt

I run the same perl command and it fails with this error:

Can't remove config.txt: Operation not permitted, skipping file.

Which is fine. However, 'echo $?' still returns 0 in this case. Why is this so? Shouldn't it return a non-zero value indicating an error?


The problem is that Perl does not come back with a non-zero exit status for this condition (sudo passes on the exit status of the command it was given), which is a bit vexing. You can work around the problem by recognizing that the line-reading loop is never entered if the file fails to be renamed and handle it with a flag:

sudo perl -i -ne 's/foo/bar/; print; $wrk = 1; }{ $wrk or exit 1' config.txt

The Eskimo greeting (or butterfly) "operator" }{ introduces an END block, in a way; what comes after it is executed when the loop reading lines from the file has ended. The way it works is described here.

The caveat is that this will also report an error if config.txt is empty. A shorter if a bit hackier way is to use the special $. line counter variable for the same purpose:

sudo perl -i -ne 's/foo/bar/; print; }{ $. or exit 1' config.txt

Need Your Help

Android <alpha> issues… image blinks?

android eclipse animation fadein alpha

My fade in code works properly, but at the end before transitioning to the main .java file it shows the image again for a second. What could I do to fix this?