I like to user colored output in my interactive shell scripts.
I've been using Ubuntu and bash for a long time, but haven't done much bash scripting.
I'd appreciate a review of this function for generating colored output.
#!/usr/bin/env bash
#
# Function to generate colored output.
#
# The output is specified using a format string and arguments, similar to printf.
#
# All special format specifiers are enclosed in parenthesis.
# Colors start with either "f" for foreground or "b" for background with the
# remainder of the specifier being the color name, starting with a capital
# letter (e.g., fRed or bCyan).
#
# There are a few other specifiers in addition to the colors:
# - %s% Placeholder; consumes the next argument from the command line
# - %u% Underline
# - %r$ Reverse video
# - %default% Default foreground and background color
# - %reset% Reset all attributes
#
# Example:
# echoc '%fRed%The value "%r%%s%%fRed%" is not valid for the --trace option' extra
# Result:
# The value "extra" is not valid for the --trace option
# with everything except the word extra being red on the default background
# color and the word extra being reverse-video.
#
unset -f echoc
function echoc()
{
local char
local code
local fmt="${1}"
local fmtLen=${#fmt}
local i=0
local output=''
local str=''
local tagActive=0
shift # Remove the format string.
#
# The ANSI color and format codes.
# Keys that start with "f" are foreground colors.
# Keys that start with "b" are background colors.
# Other keys are eight resets or other formatting codes.
# The "r" and "u" are reverse and underscore, respectively.
#
declare -A colors
colors=(['fBlack']='30' ['fBlue']='34' ['fBrown']='33' ['fCyan']='36')
colors+=(['fDarkgray']='1;30' ['fDefault']='39' ['fGreen']='32' ['fLavender']='1;34')
colors+=(['fLightblue']='1;36' ['fLightgray']='37' ['fLightgreen']='1;32')
colors+=(['fLightpurple']='1;35' ['fMagenta']='35' ['fPink']='1;31' ['fPurple']='35')
colors+=(['fRed']='31' ['fWhite']='1;37' ['fYellow']='1;33')
colors+=(['bBlack']='40' ['bBlue']='44' ['bBrown']='43' ['bCyan']='46' ['bDefault']='49')
colors+=(['bGreen']='42' ['bMagenta']='45' ['bPurple']='45' ['bRed']='41')
colors+=(['default']='39;49' ['reset']='0')
colors+=(['r']='7' ['u']='4')
#
# Parse the format string, building the output string as we go.
#
while [ $i -lt $fmtLen ]
do
char="${fmt:i:1}"
case $char in
%)
if [ 0 -eq $tagActive ]
then
if [ -n "${str}" ]
then
output="${output}${str}"
str=''
fi
tagActive=1
else # tagActive is true.
if [ -z "${str}" ]
then
output="${output}%" # %% inserts a percent sign.
else
if [ 's' == "${str}" ]
then
output="${output}${1}\033[0m"
shift
else
code="${colors[$str]}"
if [ -z "${code}" ]
then
echo -e "\033[31mInvalid color name \"${str}\"\033[0m"
else
output="${output}\033[${code}m"
fi
fi
str=''
fi
tagActive=0
fi
;;
*)
str="${str}${char}"
;;
esac
((i++))
done
if [ -n "${str}" ]
then
output="${output}${str}"
fi
output="${output}\033[0m"
echo -e "${output}"
}
export -f echoc