Is there a TRY CATCH command in Bash Is there a TRY CATCH command in Bash shell shell

Is there a TRY CATCH command in Bash


Is there a TRY CATCH command in Bash?

No.

Bash doesn't have as many luxuries as one can find in many programming languages.

There is no try/catch in bash; however, one can achieve similar behavior using && or ||.

Using ||:

if command1 fails then command2 runs as follows

command1 || command2

Similarly, using &&, command2 will run if command1 is successful

The closest approximation of try/catch is as follows

{ # try    command1 &&    #save your output} || { # catch    # save log for exception }

Also bash contains some error handling mechanisms, as well

set -e

it stops your script if any simple command fails.

And also why not if...else. It is your best friend.


Based on some answers I found here, I made myself a small helper file to source for my projects:

trycatch.sh

#!/bin/bashfunction try(){    [[ $- = *e* ]]; SAVED_OPT_E=$?    set +e}function throw(){    exit $1}function catch(){    export ex_code=$?    (( $SAVED_OPT_E )) && set +e    return $ex_code}function throwErrors(){    set -e}function ignoreErrors(){    set +e}

here is an example how it looks like in use:

#!/bin/bashexport AnException=100export AnotherException=101# start with a trytry(   # open a subshell !!!    echo "do something"    [ someErrorCondition ] && throw $AnException    echo "do something more"    executeCommandThatMightFail || throw $AnotherException    throwErrors # automaticatly end the try block, if command-result is non-null    echo "now on to something completely different"    executeCommandThatMightFail    echo "it's a wonder we came so far"    executeCommandThatFailsForSure || true # ignore a single failing command    ignoreErrors # ignore failures of commands until further notice    executeCommand1ThatFailsForSure    local result = $(executeCommand2ThatFailsForSure)    [ result != "expected error" ] && throw $AnException # ok, if it's not an expected error, we want to bail out!    executeCommand3ThatFailsForSure    echo "finished")# directly after closing the subshell you need to connect a group to the catch using ||catch || {    # now you can handle    case $ex_code in        $AnException)            echo "AnException was thrown"        ;;        $AnotherException)            echo "AnotherException was thrown"        ;;        *)            echo "An unexpected exception was thrown"            throw $ex_code # you can rethrow the "exception" causing the script to exit if not caught        ;;    esac}


I've developed an almost flawless try & catch implementation in bash, that allows you to write code like:

try     echo 'Hello'    false    echo 'This will not be displayed'catch     echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"

You can even nest the try-catch blocks inside themselves!

try {    echo 'Hello'    try {        echo 'Nested Hello'        false        echo 'This will not execute'    } catch {        echo "Nested Caught (@ $__EXCEPTION_LINE__)"    }    false    echo 'This will not execute too'} catch {    echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"}

The code is a part of my bash boilerplate/framework. It further extends the idea of try & catch with things like error handling with backtrace and exceptions (plus some other nice features).

Here's the code that's responsible just for try & catch:

set -o pipefailshopt -s expand_aliasesdeclare -ig __oo__insideTryCatch=0# if try-catch is nested, then set +e before so the parent handler doesn't catch usalias try="[[ \$__oo__insideTryCatch -gt 0 ]] && set +e;           __oo__insideTryCatch+=1; ( set -e;           trap \"Exception.Capture \${LINENO}; \" ERR;"alias catch=" ); Exception.Extract \$? || "Exception.Capture() {    local script="${BASH_SOURCE[1]#./}"    if [[ ! -f /tmp/stored_exception_source ]]; then        echo "$script" > /tmp/stored_exception_source    fi    if [[ ! -f /tmp/stored_exception_line ]]; then        echo "$1" > /tmp/stored_exception_line    fi    return 0}Exception.Extract() {    if [[ $__oo__insideTryCatch -gt 1 ]]    then        set -e    fi    __oo__insideTryCatch+=-1    __EXCEPTION_CATCH__=( $(Exception.GetLastException) )    local retVal=$1    if [[ $retVal -gt 0 ]]    then        # BACKWARDS COMPATIBILE WAY:        # export __EXCEPTION_SOURCE__="${__EXCEPTION_CATCH__[(${#__EXCEPTION_CATCH__[@]}-1)]}"        # export __EXCEPTION_LINE__="${__EXCEPTION_CATCH__[(${#__EXCEPTION_CATCH__[@]}-2)]}"        export __EXCEPTION_SOURCE__="${__EXCEPTION_CATCH__[-1]}"        export __EXCEPTION_LINE__="${__EXCEPTION_CATCH__[-2]}"        export __EXCEPTION__="${__EXCEPTION_CATCH__[@]:0:(${#__EXCEPTION_CATCH__[@]} - 2)}"        return 1 # so that we may continue with a "catch"    fi}Exception.GetLastException() {    if [[ -f /tmp/stored_exception ]] && [[ -f /tmp/stored_exception_line ]] && [[ -f /tmp/stored_exception_source ]]    then        cat /tmp/stored_exception        cat /tmp/stored_exception_line        cat /tmp/stored_exception_source    else        echo -e " \n${BASH_LINENO[1]}\n${BASH_SOURCE[2]#./}"    fi    rm -f /tmp/stored_exception /tmp/stored_exception_line /tmp/stored_exception_source    return 0}

Feel free to use, fork and contribute - it's on GitHub.