Intention
I came with the idea of generic, portable, highly reliable, and further customizable function for Shell scripts, written in POSIX, for error handling.
Purpose
The function shall find out, if the terminal has color support, and act accordingly. If it has, then I highlight the error origin and the exit code with different colors. The main message shall be tabbed from the left, all for the best readability.
Example function call and error handler output (textual) + Explanation
print_usage_and_exit
is a self-explanatory function, which watches over the number of given arguments, it accepts exactly one, let's give it some more:
Example function:
print_usage_and_exit()
{
# check if exactly one argument has been passed
[ "${#}" -eq 1 ] || print_error_and_exit 1 "print_usage_and_exit" "Exactly one argument has not been passed!\\n\\tPassed: ${*}"
# check if the argument is a number
is_number "${1}" || print_error_and_exit 1 "print_usage_and_exit" "The argument is not a number! Exit code expected."
echo "Usage: ${0} [-1]"
echo " -1: One-time coin collect."
echo "Default: Repeat coin collecting until interrupted."
exit "${1}"
}
Example function call - erroneous:
print_usage_and_exit a b c 1 2 3
Example output:
print_usage_and_exit()
Exactly one argument has not been passed!
Passed: a b c 1 2 3
exit code = 1
Example error handler output (visual)
The actual error handler function code
print_error_and_exit()
# expected arguments:
# $1 = exit code
# $2 = error origin (usually function name)
# $3 = error message
{
# check if exactly 3 arguments have been passed
# if not, print out an internal error without colors
if [ "${#}" -ne 3 ]
then
printf "print_error_and_exit() internal error\\n\\n\\tWrong number of arguments has been passed: %b!\\n\\tExpected the following 3:\\n\\t\\t\$1 - exit code\\n\\t\\t\$2 - error origin\\n\\t\\t\$3 - error message\\n\\nexit code = 1\\n" "${#}" 1>&2
exit 1
fi
# check if the first argument is a number
# if not, print out an internal error without colors
if ! [ "${1}" -eq "${1}" ] 2> /dev/null
then
printf "print_error_and_exit() internal error\\n\\n\\tThe first argument is not a number: %b!\\n\\tExpected an exit code from the script.\\n\\nexit code = 1\\n" "${1}" 1>&2
exit 1
fi
# check if we have color support
if [ -x /usr/bin/tput ] && tput setaf 1 > /dev/null 2>&1
then
# colors definitions
readonly bold=$(tput bold)
readonly red=$(tput setaf 1)
readonly yellow=$(tput setaf 3)
readonly nocolor=$(tput sgr0)
# combinations to reduce the number of printf references
readonly bold_red="${bold}${red}"
readonly bold_yellow="${bold}${yellow}"
# here we do have color support, so we highlight the error origin and the exit code
printf "%b%b()\\n\\n\\t%b%b%b\\n\\nexit code = %b%b\\n" "${bold_yellow}" "${2}" "${nocolor}" "$3" "${bold_red}" "${1}" "${nocolor}" 1>&2
exit "$1"
else
# here we do not have color support
printf "%b()\\n\\n\\t%b\\n\\nexit code = %b\\n" "${2}" "${3}" "${1}" 1>&2
exit "$1"
fi
}
EDIT
I realized the tput
could very well be anywhere else than in /usr/bin/
.
So, while keeping the original code untouched, I have changed the line:
if [ -x /usr/bin/tput ] && tput setaf 1 > /dev/null 2>&1
to a more plausible check:
if command -v tput > /dev/null 2>&1 && tput setaf 1 > /dev/null 2>&1