Is there a way to write a Bash function which aborts the whole execution, no matter how it is called?

BashFunctionExitSubshell

Bash Problem Overview


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....

But 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).

Bash Solutions


Solution 1 - Bash

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".

Solution 2 - Bash

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 $?

Solution 3 - Bash

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
}

Solution 4 - Bash

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"

Solution 5 - Bash

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 $?

Solution 6 - Bash

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".

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLiMarView Question on Stackoverflow
Solution 1 - BashFatalErrorView Answer on Stackoverflow
Solution 2 - BashbriceView Answer on Stackoverflow
Solution 3 - BashDaenythView Answer on Stackoverflow
Solution 4 - BashAmazingAlexView Answer on Stackoverflow
Solution 5 - BashLucaView Answer on Stackoverflow
Solution 6 - BashJohnView Answer on Stackoverflow