I'm writing a script in Bash to test some code. However, it seems silly to run the tests if compiling the code fails in the first place, in which case I'll just abort the tests.
Is there a way I can do this without wrapping the entire script inside of a while loop and using breaks? Something like a dun dun dun goto?
Try this statement:
Replace
1
with appropriate error codes. See also Exit Codes With Special Meanings.A bad-arse SysOps guy once taught me the Three-Fingered Claw technique:
These functions are *NIX OS and shell flavor-robust. Put them at the beginning of your script (bash or otherwise),
try()
your statement and code on.Explanation
(based on flying sheep comment).
yell
: print the script name and all arguments tostderr
:$0
is the path to the script ;$*
are all arguments.>&2
means>
redirect stdout to & pipe2
. pipe1
would bestdout
itself.die
does the same asyell
, but exits with a non-0 exit status, which means “fail”.try
uses the||
(booleanOR
), which only evaluates the right side if the left one didn’t fail.$@
is all arguments again, but different.Hope that explains everything.
Use set -e
The script will terminate after the first line that fails (returns nonzero exit code). In this case, command-that-fails2 will not run.
If you were to check the return status of every single command, your script would look like this:
With set -e it would look like:
Any command that fails will cause the entire script to fail and return an exit status you can check with $?. If your script is very long or you're building a lot of stuff it's going to get pretty ugly if you add return status checks everywhere.
Instead of
if
construct, you can leverage the short-circuit evaluation:Note the pair of parentheses which is necessary because of priority of alternation operator.
$?
is a special variable set to exit code of most recently called command.I have the same question but cannot ask it because it would be a duplicate.
The accepted answer, using exit, does not work when the script is a bit more complicated. If you use a background process to check for the condition, exit only exits that process, as it runs in a sub-shell. To kill the script, you have to explicitly kill it (at least that is the only way I know).
Here is a little script on how to do it:
This is a better answer but still incomplete a I really don't know how to get rid of the boom part.
I often include a function called run() to handle errors. Every call I want to make is passed to this function so the entire script exits when a failure is hit. The advantage of this over the set -e solution is that the script doesn't exit silently when a line fails, and can tell you what the problem is. In the following example, the 3rd line is not executed because the script exits at the call to false.