Reputation: 2972
I was using the "exit 1" statement in my Bash functions to terminate the whole script and it worked fine:
function func()
{
echo "Goodbye"
exit 1
}
echo "Function call will abort"
func
echo "This will never be printed"
But then I realized that it doesn't do the work when called like:
res=$(func)
I understand that I created a subshell and "exit 1" aborts that subshell and not the primary one; is there a way to write a function which aborts the whole execution, no matter how it is called?
I just need to get the real return value (echoed by the function).
Upvotes: 114
Views: 73123
Reputation: 1
This works and is "clean" without a lot of extra hoops, make sure the top level function is defined with parenthesis instead of curly braces. This provides 1) immediate exit as well as 2) the exit status is available:
TestExitAllFunctions ()
(
function FatalError ()
{
echo "$1" 1>&2;
exit 1
};
echo "Function call will abort";
FatalError "Oops, fatal error found, sorry";
echo "This will never be printed"
)
TestExitAllFunctions
Function call will abort
Oops, fatal error found, sorry
echo $?
1
Upvotes: -1
Reputation: 21
If you just need top be able to bomb out of your scripts from within a function, you can do:
function die () {
set -e
/bin/false
}
then elsewhere, within your functions, instead of using "exit", use "die".
Upvotes: 2
Reputation: 29
I guess better is
#!/bin/bash
set -e
trap "exit 1" ERR
myfunc() {
set -x # OPTIONAL TO SHOW ERROR
echo "Exit with failure"
set +x # OPTIONAL
exit 1
}
echo "BEFORE..."
myvar="$(myfunc)"
echo "AFTER..But not shown"
Upvotes: 2
Reputation: 25039
You can use set -e
which exits if a command exits with a non-zero status:
set -e
func
set +e
Or grab the return value:
(func) || exit $?
Upvotes: 57
Reputation: 54611
What you could do, is register the top level shell for the TERM
signal to exit, and then send a TERM
to the top level shell:
#!/bin/bash
trap "exit 1" TERM
export TOP_PID=$$
function func()
{
echo "Goodbye"
kill -s TERM $TOP_PID
}
echo "Function call will abort"
echo $(func)
echo "This will never be printed"
So, your function sends a TERM
signal back to the top level shell, which is caught and handled using the provided command, in this case, "exit 1"
.
Upvotes: 129
Reputation: 4273
But is there a way to write a function which aborts the whole execution, no matter how it is called?
No.
I just need to get the real return value (echoed by the function).
You can
res=$(func)
echo $?
Upvotes: 0
Reputation: 37461
A child process can't force the parent process to close implicitly. You need to use some kind of signaling mechanism. Options might include a special return value, or perhaps sending some signal with kill
, something like
function child() {
local parent_pid="$1"
local other="$2"
...
if [[ $failed ]]; then
kill -QUIT "$parent_pid"
fi
}
Upvotes: 3