Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl - Why exit code 0 if error file not found, can I make it code 1?

Tags:

perl

I have a several logical AND commands and in the middle is a perl command that edits a file in-place.

echo before && \
perl -pe 's/foo/bar/g' -i qux && \
echo after

If the file does not exist perl will die with "Can't open qux: No such file or directory." But the error code is 0. That is a problem because I don't want the command to continue. In other words 'after' shouldn't print if the file doesn't exist. Why is that happening and how can I stop it?

like image 623
newguy Avatar asked Aug 28 '16 04:08

newguy


People also ask

What is Exit code 1?

What is Exit Code 1. Exit Code 1 indicates that a container shut down, either because of an application failure or because the image pointed to an invalid file. In a Unix/Linux operating system, when an application terminates with Exit Code 1, the operating system ends the process using Signal 7, known as SIGHUP.

What does Exit status 1 mean in java?

exit(0) by convention, a zero status code indicates successful termination. System.exit(1) -It means termination unsuccessful due to some error.


2 Answers

You might use perl -pe ... < file instead of perl -pe ... file. In this case the shell will already complain if the file does not exist without even invoking perl. But this can not be used together with the -i switch.

Or since you want to use the -i switch you might check that the file is writable before using it. Not that this checks for qux being both file and writable because being only one of these is not enough (maybe one needs to check for readable too).

[ -f qux ] && [ -w qux ] && perl -pe ... -i qux
like image 90
Steffen Ullrich Avatar answered Nov 15 '22 08:11

Steffen Ullrich


OK, so...

As mentioned in comments to the question, the reason perl exits with a 0 is because perl itself was successful, even if the code executed by perl was not. In order to get it to exit with a failure, then, we need to find a way to make it die (or explicitly exit with a non-zero status) if the file can't be opened.

But perl -p wraps a loop around your one-liner, so can we do that without having to repeat the test on every line? Yes, we can! perldoc perlrun tells us that BEGIN and END blocks allow us to take control before or after the loop executes.

But we still need a way to tell whether the file was successfully opened. To do that, we need to know the name of the filehandle used by <>, which perldoc perlvar tells us is called ARGV.

But ARGV is only (reliably) magical when it's read from, so we can't just test for whether it's defined because (in my quick testing) it's always defined, even if the file is missing. So we have to read from it. And then the first line is lost. But that's easily fixed by seeking back to the start of the file.

TL;DR and the upshot of all that:

echo before && \
perl -pe 'BEGIN { exit 1 unless <> ; seek ARGV,0,0 } s/foo/bar/g' -i qux && \
echo after

Note that this still isn't 100% perfect. It will also die if the file exists, but is empty. Checking defined <> doesn't fix this flaw and attempting to <> ; die unless ARGV causes <> to read from STDIN if the file doesn't exist. If anyone has a way to get it to correctly detect empty files, I'd be very interested to hear about it!

like image 44
Dave Sherohman Avatar answered Nov 15 '22 09:11

Dave Sherohman