I have a simple script with a simple function which can lead to an error. Let's define this function, and make it broken:
brokenFunction () {
ls "non-existing-folder"
}
If we execute this function in a block detecting if it is broken, it works well:
brokenFunction || printf "It is broken\n"
prints "It is broken"
Now, let's make the function a bit more complex, by adding a correct command at the end :
#!/bin/sh
brokenFunction () {
ls "non-existing-folder"
printf "End of function\n"
}
brokenFunction || printf "It is broken\n"
This script prints :
$ ./script.sh
ls: cannot access 'non-existing-folder': No such file or directory
End of function
while I expected the function to stop before the printf statement, and the next block to display "It is broken".
And indeed, if I check the exit status code of brokenFunction
, it is 0.
I tried adding set -e
to the top of the script. The behavior is still the same, but the exit code of brokenFunction
if called without ||
now becomes 2
. If called with it, the status code is still 0
.
Is there any way to keep the set -e
setting inside a function called with ||
?
EDIT: I just realized that the function in the example was useless. I encounter the same issue with a simple block and a condition.
#!/bin/sh
set -e
{
ls "non-existing-dir"
printf "End of block\n"
} || {
printf "It is broken\n"
}
prints
$ ./script.sh
ls: cannot access 'non-existing-dir': No such file or directory
End of block
As written in man bash
, set -e
is ignored in some contexts. A command before ||
or &&
is such a context.
trap
looks like a possible solution here. A working alternative to the last script using trap
would look like that:
#!/bin/sh
abort () {
printf "It is broken\n"
}
trap 'abort' ERR
(
set -e
false
printf "End of block\n"
)
trap - ERR
Some things have to be noticed here:
trap 'abort' ERR
binds the abort
function to any raised error ;set -e
effect), and not the whole script ;trap - ERR
at the end resets the trap
binding, meaning the following part of the script is executed as before.To test the border effects, we can add the previously non-working part :
#!/bin/sh
abort () {
printf "It is broken\n"
}
trap 'abort' ERR
(
set -e
false
printf "End of block\n"
)
trap - ERR
{
false
printf "End of second block\n"
} || {
printf "It is broken too\n"
}
prints:
It is broken
End of second block