I am trying to run a list of commands, stop on the first error (non-zero return code) and run some error handling if this happens.
My current solution:
set -e
set -o pipefail
(
cmd1
cmd2
...
)
So far so good, the command stops at the first error. But if I add a catcher:
set -e
set -o pipefail
(
cmd1
cmd2
) || ( failure_catcher )
Then even if cmd1 fails, cmd2 is still called! It looks like the first subshell is affected by the presence of the catcher.
For a testable example:
set -e
set -o pipefail
(
false
echo "After failure"
) || ( echo "Failed" )
Prints "After failure", while I would expect it to print "Failed". Even if I add set -e at the start of the subshell, it still prints "After failure".
I'm clearly missing something fundamental in the way bash handles sub-shells. I'm now looking into alternative solutions, using trap handlers for the failure catcher, but what is wrong with the sub-shell catcher here?
EDIT: I might have found a way:
runit() {
false
echo "After failure"
}
export -f runit
(
bash -e -o pipefail -c runit
) || ( echo "Failed" )
This still lets me embed any valid bash script inside the runit function, preserving the -e option there.
||puts the subshell in a context where-edoesn't apply. You'll need to use&&instead of newline or;in the subshell.-ein there? EDIT: Ah I may have found a way - define and export a function with the commands, then runbash -c the_function_nameinstead of the commands - in there,set -ewill properly work.The shell does not exit if the command that fails is part of the command list immediately following a while or until reserved word, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||...-- Bash Manual (I think more or less the idea is that, it will not exit when the "semantics" is that the failed command is a just "test" in a conditional. When you have|| catcher, you made the "subshell" such a "test" -- not so sure if "subshell" or not even matters here)bash -e -c $my_functionis quite different to just forking a subshell.