ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
When I use, say, ${BOLDYELLOW} directly I get the color but when I pass the text string BOLDYELLOW I can't reformat that string into the variable ${BOLDYELLOW}. That is,
Now... none of this is portable AT ALL... and you really need to look into making terminfo calls to get the escapes rather than hard coding them. man tput and man terminfo and man infocmp and possibly man tic
I was wondering, why not just create a function for each particular task:
I had considered that idea.
I use the shell-colors container in almost all of my shell scripts and likewise in the script I was revising. In my revisions I noticed a lot of repetitive code with respect to user informational messaging. I consolidated that repetition into a simple function I could call. Much nicer and more efficient, of course.
In that script I noticed I had about 8 or 9 snippets where I could not use my new function, but if I could pass the desired color as an argument/parameter I could augment my new function with an elif statement.
I could have created a separate color functions for this one script but that would have been less efficient than just using the color variables directly inline.
Since you're after efficiency I also thought about sharing my codes. This is part of playshell:
log.sh
Code:
include available.sh
include assume.sh
include console.sh
include debug.sh
include env.sh
include misc.sh
include useextglob.sh
#
# log.sh
#
# provides the logging framework of playshell
#
# author: konsolebox
# copyright free
# created and updated 2006-2010
#
LOG_LEVELS_SILENT=0 ## no output even warnings and errors
LOG_LEVELS_QUIET=1 ## output only warnings and errors
LOG_LEVELS_NORMAL=2 ## normal
LOG_LEVELS_VERBOSE=3 ## include verbose messages
LOG_LEVELS_DEBUG=4 ## include debug messages and all other messages
LOG_ID_MSG=0
LOG_ID_INF=1
LOG_ID_WRN=2
LOG_ID_ERR=3
LOG_ID_VER=4
LOG_ID_DBG=5
LOG_ID_IMS=6
LOG_FUNCTIONS=(
[LOG_ID_MSG]=log_message
[LOG_ID_IMS]=log_imessage
[LOG_ID_INF]=log_info
[LOG_ID_WRN]=log_warning
[LOG_ID_ERR]=log_error
[LOG_ID_VER]=log_verbose
[LOG_ID_DBG]=log_debug
)
LOG_FUNCTIONS_LEVELS=(
[LOG_ID_MSG]=$LOG_LEVELS_NORMAL
[LOG_ID_IMS]=$LOG_LEVELS_SILENT
[LOG_ID_INF]=$LOG_LEVELS_NORMAL
[LOG_ID_WRN]=$LOG_LEVELS_QUIET
[LOG_ID_ERR]=$LOG_LEVELS_QUIET
[LOG_ID_VER]=$LOG_LEVELS_VERBOSE
[LOG_ID_DBG]=$LOG_LEVELS_DEBUG
)
LOG_FUNCTIONS_COLORS_DEFAULT=(
[LOG_ID_MSG]=$CONSOLE_HI_GREEN
[LOG_ID_IMS]=$CONSOLE_HI_GREEN
[LOG_ID_INF]=$CONSOLE_HI_WHITE
[LOG_ID_WRN]=$CONSOLE_HI_YELLOW
[LOG_ID_ERR]=$CONSOLE_HI_RED
[LOG_ID_VER]=$CONSOLE_GREEN
[LOG_ID_DBG]=$CONSOLE_HI_CYAN
)
LOG_FUNCTIONS_COLORS_NONE=(
[LOG_ID_MSG]=
[LOG_ID_IMS]=
[LOG_ID_INF]=
[LOG_ID_WRN]=
[LOG_ID_ERR]=
[LOG_ID_VER]=
[LOG_ID_DBG]=
)
LOG_FUNCTIONS_COLORS=(
"${LOG_FUNCTIONS_COLORS_DEFAULT[@]}"
)
LOG_LEVEL=$LOG_LEVELS_NORMAL
LOG_USEESCAPECODES=true
LOG_WRAPCOLUMNS=72
# void log_configure (["mode=<MODE>"][, "colors=<COLORSVAR>|true|false|none"][, "escapecodes=true|false"][, "@no-setup")
#
function log_configure {
local SETUP=true
assume "\$2 == @(mode=@(debug|verbose|normal|quiet|silent)|colors=@(+([[:alpha:]])*([[:digit:]_])|true|false|none)|escapecodes=@(true|false))" "$1"
while [[ $# -gt 0 ]]; do
case "$1" in
mode=*)
case "${1#mode=}" in
debug)
LOG_LEVEL=$LOG_LEVELS_DEBUG
;;
verbose)
LOG_LEVEL=$LOG_LEVELS_VERBOSE
;;
normal)
LOG_LEVEL=$LOG_LEVELS_NORMAL
;;
quiet)
LOG_LEVEL=$LOG_LEVELS_QUIET
;;
silent)
LOG_LEVEL=$LOG_LEVELS_SILENT
;;
esac
;;
colors=*)
case "${1#colors=}" in
false|none)
LOG_FUNCTIONS_COLORS=(${LOG_FUNCTIONS_COLORS_NONE})
;;
true)
LOG_FUNCTIONS_COLORS=("${LOG_FUNCTIONS_COLORS_DEFAULT[@]}")
;;
*)
eval "LOG_FUNCTIONS_COLORS=(\"\${${1#colors=}[@]}\")"
;;
esac
;;
escapecodes=*)
LOG_USEESCAPECODES=${1#escapecodes=}
;;
@no-setup)
SETUP=false
;;
esac
shift
done
[[ $SETUP = true ]] && log_setup
}
# void log_setup (void)
#
function log_setup {
local NAME COLOR PREFIX TEMPLATE FUNCTION WRAPTEMPLATE0 WRAPTEMPLATE1
local -i LEVEL INDEX
local -a TEMPLATES=()
# normal functions
if [[ LOG_LEVEL -ge LOG_LEVELS_DEBUG ]]; then
PREFIX='${FUNCNAME[1]}: '
else
PREFIX=''
fi
for INDEX in ${!LOG_FUNCTIONS[@]}; do
NAME=${LOG_FUNCTIONS[INDEX]}
LEVEL=${LOG_FUNCTIONS_LEVELS[INDEX]}
COLOR=${LOG_FUNCTIONS_COLORS[INDEX]}
if [[ LEVEL -le LOG_LEVEL ]]; then
if [[ $LOG_USEESCAPECODES = false ]]; then
TEMPLATE="<MESSAGE>"
elif [[ -n $COLOR ]]; then
TEMPLATE="${CONSOLE_NORMAL}${COLOR}<MESSAGE>${CONSOLE_NORMAL}"
else
TEMPLATE="${CONSOLE_NORMAL}<MESSAGE>"
fi
eval "function $NAME { echo -e \"${TEMPLATE/'<MESSAGE>'/${PREFIX}\$1}\"; LOG_LASTLEVEL=$LEVEL; }"
else
TEMPLATE=''
eval "function $NAME { LOG_LASTLEVEL=$LEVEL; }"
fi
TEMPLATES[INDEX]=$TEMPLATE
done
# special function log_fcall()
if [[ LOG_LEVELS_DEBUG -le LOG_LEVEL ]]; then
TEMPLATE=${TEMPLATES[LOG_ID_DBG]/'<MESSAGE>'/'$MESSAGE'}
eval "
function log_fcall {
local MESSAGE
if [[ \$# -eq 1 ]]; then
MESSAGE=\"\${FUNCNAME[1]}( \\\"\$1\\\" )\"
elif [[ \$# -gt 1 ]]; then
local LASTARG=\${!#}
local -a ARGSTEMP=(\"\${@:1:\$(( \$# - 1 ))}\")
ARGSTEMP=(\"\${ARGSTEMP[@]/#/\\\"}\")
MESSAGE=\"\${FUNCNAME[1]}( \${ARGSTEMP[@]/%/\\\",} \\\"\${LASTARG}\\\" )\"
else
MESSAGE=\"\${FUNCNAME[1]}()\"
fi
echo -e \"${TEMPLATE}\"
LOG_LASTLEVEL=$LOG_LEVELS_DEBUG
}
"
else
eval "function log_fcall { LOG_LASTLEVEL=${LOG_LEVELS_DEBUG}; }"
fi
# special function log_finalerror()
if [[ LOG_LEVELS_ERROR -le LOG_LEVEL ]]; then
TEMPLATE=${TEMPLATES[LOG_ID_ERR]/'<MESSAGE>'/'$1'}
eval "
function log_finalerror {
echo \"$TEMPLATE\"
exit \"\${2:-1}\"
}
"
else
function log_finalerror { exit "${2:-1}"; }
fi
# special function log_fatalerror()
if [[ LOG_LEVELS_ERROR -le LOG_LEVEL ]]; then
TEMPLATE=${TEMPLATES[LOG_ID_ERR]/'<MESSAGE>'/'${MESSAGE[*]}'}
eval "
function log_fatalerror {
local -a MESSAGE=()
local -i L=0 F
MESSAGE[L++]=\"${PREFIX}fatal error: \${FUNCNAME[1]}(): \$1\"
MESSAGE[L++]=''
MESSAGE[L++]='function call stack:'
MESSAGE[L++]=''
for (( F = \${#FUNCNAME[@]}; F--; )); do
MESSAGE[L++]=\$'\\t'\"\${FUNCNAME[F]}()\"
done
MESSAGE[L++]=''
local IFS=\$'\\n'
echo \"$TEMPLATE\"
exit \"\${2:-1}\"
}
"
else
function log_fatalerror { exit "${2:-1}"; }
fi
# wrapped versions
WRAPTEMPLATE0="
function <NAME0> {
local WRAPPED
utils_parawrap \"\$1\" WRAPPED \"\${2:-${LOG_WRAPCOLUMNS}}\"
local -i I
for I in \${!WRAPPED[@]}; do
<NAME1> \"\${WRAPPED[I]}\"
done
}
"
WRAPTEMPLATE1="
function <NAME0> {
LOG_LASTLEVEL=<LEVEL>
}
"
for INDEX in ${!LOG_FUNCTIONS[@]}; do
NAME=${LOG_FUNCTIONS[INDEX]}
LEVEL=${LOG_FUNCTIONS_LEVELS[INDEX]}
FUNCTION=${WRAPTEMPLATE0/<NAME0>/"${NAME}_wrapped"}
if [[ LEVEL -le LOG_LEVEL ]]; then
FUNCTION=${FUNCTION/<NAME1>/"$NAME"}
else
FUNCTION=${FUNCTION/<LEVEL>/"$LEVEL"}
fi
eval "$FUNCTION"
done
}
# void log_checkterminal (void)
#
function log_checkterminal {
if available tput; then
if [[ -z $(tput reset) || ! $(tput colors) = 8 ]]; then
LOG_USEESCAPECODES=false
LOG_USECOLORS=false
fi
fi
}
# void log (string TEXT, ["color=<COLOR>"], ["level=<LEVEL>"])
#
# the generic logging function
#
function log {
local COLOR='' LEVEL=$LOG_LEVELS_NORMAL A
for A; do
case "$A" in
color=*)
COLOR=${A#color=}
case "$COLOR" in
message)
COLOR=${LOG_FUNCTIONS_COLORS[LOG_ID_MSG]}
;;
info)
COLOR=${LOG_FUNCTIONS_COLORS[LOG_ID_INF]}
;;
warning)
COLOR=${LOG_FUNCTIONS_COLORS[LOG_ID_WRN]}
;;
error)
COLOR=${LOG_FUNCTIONS_COLORS[LOG_ID_ERR]}
;;
verbose)
COLOR=${LOG_FUNCTIONS_COLORS[LOG_ID_VER]}
;;
debug)
COLOR=${LOG_FUNCTIONS_COLORS[LOG_ID_DBG]}
;;
#beginoptionalblock
$'\e'\[*)
;;
*)
echo "log: invalid parameter to color: $COLOR"
exit 1
;;
esac
#endoptionalblock
;;
level=*)
LEVEL=${A#level=}
case "$LEVEL" in
silent)
LEVEL=$LOG_LEVELS_SILENT
;;
quiet)
LEVEL=$LOG_LEVELS_QUIET
;;
normal)
LEVEL=$LOG_LEVELS_NORMAL
;;
verbose)
LEVEL=$LOG_LEVELS_VERBOSE
;;
debug)
LEVEL=$LOG_LEVELS_DEBUG
;;
#beginoptionalblock
+([[:digit:]]))
;;
*)
echo "log: invalid parameter to level: $LEVEL"
exit 1
;;
#endoptionalblock
esac
;;
esac
done
if [[ LEVEL -le LOG_LEVEL ]]; then
if [[ $LOG_USEESCAPECODES = false ]]; then
echo -e "$1"
elif [[ -n $COLOR ]]; then
echo -e "${CONSOLE_NORMAL}${COLOR}${1}${CONSOLE_NORMAL}"
else
echo -e "${CONSOLE_NORMAL}${1}"
fi
fi
LOG_LASTLEVEL=$LEVEL
}
# void log_message (string TEXT)
#
function log_message {
:
}
# void log_imessage (string TEXT)
#
function log_imessage {
:
}
# void log_info (string TEXT)
#
function log_info {
:
}
# void log_warning (string TEXT)
#
function log_warning {
:
}
# void log_error (string TEXT)
#
function log_error {
:
}
# void log_verbose (string TEXT)
#
function log_verbose {
:
}
# void log_debug (string TEXT)
#
function log_debug {
:
}
# void log_fcall ([string ARGS])
#
function log_fcall {
:
}
# void log_finalerror (string FUNCTION, [int EXITCODE])
#
function log_finalerror {
:
}
# void log_fatalerror (string FUNCTION, [int EXITCODE])
#
function log_fatalerror {
:
}
# void log_newline (void)
#
# creates a newline with level based on the last level
#
function log_newline {
[[ LOG_LEVEL -ge LOG_LASTLEVEL ]] && echo
}
# bool log_checklevel (string IDENT, ...)
#
# where IDENT can be any of the significant part of the name of the
# supported functions like message, imessage, info, error, warning,
# verbose, debug, fcall, finalerror and criticalerror, any of the valid
# levels like silent, quiet, normal, verbose, debug or just any number.
#
# More than one IDENT can be specified.
#
# If one of the IDENTs represents a level that is lower than the current
# level, this function returns true or false if none otherwise.
#
function log_checklevel {
local -i LEVEL
for A; do
case "$1" in
message)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_MSG]}
;;
info)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_INF]}
;;
warning)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_WRN]}
;;
error)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_ERR]}
;;
verbose)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_VER]}
;;
debug)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_DBG]}
;;
imessage)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_IMS]}
;;
finalerror)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_ERR]}
;;
criticalerror)
LEVEL=${LOG_FUNCTIONS_LEVELS[LOG_ID_ERR]}
;;
silent)
LEVEL=${LOG_LEVELS_SILENT}
;;
quiet)
LEVEL=${LOG_LEVELS_QUIET}
;;
normal)
LEVEL=${LOG_LEVELS_NORMAL}
;;
verbose)
LEVEL=${LOG_LEVELS_VERBOSE}
;;
debug)
LEVEL=${LOG_LEVELS_DEBUG}
;;
+([[:digit:]]))
LEVEL=$1
;;
#beginoptionalblock
*)
echo "log_checklevel: invalid parameter: $LEVEL"
exit 1
;;
#endoptionalblock
esac
[[ LEVEL -le LOG_LEVEL ]] && return 0
done
return 1
}
{
[[ $DEBUG = true ]] && LOG_LEVEL=$LOG_LEVELS_DEBUG
log_checkterminal
log_setup
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.