3

Here is an example script:

#!/bin/bash
set -euo pipefail

function_test () {
        echo "Everything still ok."
        thisdoesnotexist
        echo "It continues running..."
}

function_test || { echo "Error occured in function_test."; exit 1; }

I expect this script to exit on "thisdoesnotexist", since set -e is activated. Either the error message "Error occured in function_test." should appear, or at least the script should be exited. What happens instead, is that the script keeps running:

$ ./testscript.sh 
Everything still ok.
./testscript.sh: Zeile 6: thisdoesnotexist: Kommando nicht gefunden.
It continues running...

I figure this is because I'm using the function in an "or" (||) context, according to the manual for set:

Exit immediately [...] unless the command that fails is part of an until or while loop, part of an if statement, part of a && or || list, [...]

What would be the best way to handle this in a script? I have removed the "||" and used an error trap like this:

#!/bin/bash
set -Eeuo pipefail

errorhandler () {
        echo "Errorhandler called. Exiting."
        exit 1
}

trap "errorhandler" ERR

function_test () {
        echo "Everything still ok."
        thisdoesnotexist
        echo "It continues running..."
}

function_test

Which does work:

$ ./testscript.sh 
Everything still ok.
./testscript.sh: Zeile 13: thisdoesnotexist: Kommando nicht gefunden.
Errorhandler called. Exiting.

In this case though it seems impossible to output a user friendly message (which, for example, contains the step in the script, where the error happened). For this I would at least have to pass on the function name to the error trap. I tried that but found no working solution.

Do you have a better suggestion?

0

3 Answers 3

2

function_test || { echo "Error occured in function_test."; exit 1; }

The OR never happens because of the functions return status. The last echo statement from the function causes a return status of 0, since it successfully ran.

If you add a non-zero return on the command that isn't successful, then it will cause the OR statement to run properly.

function_test () {
        echo "Everything still ok."
        thisdoesnotexist || return 1;
        echo "It continues running..."
}
Sign up to request clarification or add additional context in comments.

Comments

0

Not very expendable, but preferable in some cases. Export flags and your function, and run it in a subshell. Handle bash error value.

#!/bin/bash
set -euo pipefail

function_test () {
    echo "Everything still ok."
    thisdoesnotexist
    echo "It continues running..."
}

export -f function_test
export SHELLOPTS
bash -c function_test || { echo "Error occured in function_test."; exit 1; }

Comments

0

If you want to do stuffs in case of error and you know something may go wrong then:

function_test () {
        echo "Everything still ok."
        thisdoesnotexist || {
          # handle thisdoesnotexist failure
          Echo "thisdoesnotexist failed" >&2
          exit 1
        }
        echo "It continues running..."
        if ! thisdoesnotexisteither; then
          # Handle fail for thisdoesnotexisteither
          Echo "thisdoesnotexisteither failed" >&2
          exit 1
        fi
}

Now for the purpose of testing error handling in Bash, you can use this intelligent erroring function:

#!/usr/bin/env bash

# Generate an error
# @Params
# $1: Numeric error return code
# ${2[@]}: Messages
# @Output
# &1: Generic success message
# &2: Generic or passed error messages
# @Return
# $?: Intended return code
erroring() {
  local rc=1
  if [ "$#" -gt 0 ]; then
    rc="$1"
    shift
    if printf '%d' "$rc" >/dev/null 2>&1; then
      # rc is an integer
      if [ "$rc" -gt 0 ]; then
        printf $"Intended failure with code: %d\\n" "$rc" >&2
        if [ "$#" -gt 0 ]; then
          # There are supplied messages to print"
          printf $"%d messages:\\n" "$#" >&2
          printf '%q\n' "$@" >&2
        fi
      else
        echo $"Intended success"
      fi
    else
      printf $"Invalid non-numeric return code parameter: %q\\n" "$rc" >&2
      rc=7
    fi
  else
    erroring "$rc"
  fi
  return "$rc"
}

2 Comments

the last printf $'Invalid - this is intended to be printf $"Invalid ? What is the point of calling erroring recursively? Wouldn't just if [ "$#" -gt 0 ]; then rc=$1; else rc=1; fi be simpler?
This is sugar for the erroring function to fail on its own way because it was passed a non-numeric return code. Like calling erroring "Error message" rather than calling erroring 1 "Error message"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.