Elegant way for verbose mode in scripts?
Solution 1
As you noticed, you can define some log
functions like log
, log_debug
, log_error
, etc.
function log () {
if [[ $_V -eq 1 ]]; then
echo "$@"
fi
}
It can help increasing your main code readability and hide show\nonshow logic into logging function.
log "some text"
If _V
(global variable) is equal 1
"some text" will be printed, in other case it will not.
Solution 2
After reading all other posts I came up with this
# set verbose level to info
__VERBOSE=6
declare -A LOG_LEVELS
# https://en.wikipedia.org/wiki/Syslog#Severity_level
LOG_LEVELS=([0]="emerg" [1]="alert" [2]="crit" [3]="err" [4]="warning" [5]="notice" [6]="info" [7]="debug")
function .log () {
local LEVEL=${1}
shift
if [ ${__VERBOSE} -ge ${LEVEL} ]; then
echo "[${LOG_LEVELS[$LEVEL]}]" "$@"
fi
}
Then you can simply use it like this
# verbose error
.log 3 "Something is wrong here"
Which will output
[error] Something is wrong here
Solution 3
#!/bin/bash
# A flexible verbosity redirection function
# John C. Petrucci (http://johncpetrucci.com)
# 2013-10-19
# Allows your script to accept varying levels of verbosity flags and give appropriate feedback via file descriptors.
# Example usage: ./this [-v[v[v]]]
verbosity=2 #Start counting at 2 so that any increase to this will result in a minimum of file descriptor 3. You should leave this alone.
maxverbosity=5 #The highest verbosity we use / allow to be displayed. Feel free to adjust.
while getopts ":v" opt; do
case $opt in
v) (( verbosity=verbosity+1 ))
;;
esac
done
printf "%s %d\n" "Verbosity level set to:" "$verbosity"
for v in $(seq 3 $verbosity) #Start counting from 3 since 1 and 2 are standards (stdout/stderr).
do
(( "$v" <= "$maxverbosity" )) && echo This would display $v
(( "$v" <= "$maxverbosity" )) && eval exec "$v>&2" #Don't change anything higher than the maximum verbosity allowed.
done
for v in $(seq $(( verbosity+1 )) $maxverbosity ) #From the verbosity level one higher than requested, through the maximum;
do
(( "$v" > "2" )) && echo This would not display $v
(( "$v" > "2" )) && eval exec "$v>/dev/null" #Redirect these to bitbucket, provided that they don't match stdout and stderr.
done
# Some confirmations:
printf "%s\n" "This message is seen at verbosity level 3 and above." >&3
printf "%s\n" "This message is seen at verbosity level 4 and above." >&4
printf "%s\n" "This message is seen at verbosity level 5 and above." >&5
Solution 4
I also came up with this function to do a quick ifelse:
function verbose () {
[[ $_V -eq 1 ]] && return 0 || return 1
}
This executes a command if $_V is set to 1. Use it like this:
verbose && command #command will be executed if $_V == 1
or
verbose && command -v || command # execute 'command -v' if $_V==1, else execute 'command'
Solution 5
If you want to avoid doing an "if" statement every single time you want to log something, you can try this approach (which is how I do it).
The idea is that instead of calling log
, you call $echoLog
instead. So, if you are in verbose mode, $echoLog
will just be echo
, but in non-verbose mode, it is a function that prints nothing and just ignores the arguments.
Here's some code you can copy.
# Use `$echoLog` everywhere you print verbose logging messages to console
# By default, it is disabled and will be enabled with the `-v` or `--verbose` flags
declare echoLog='silentEcho'
function silentEcho() {
:
}
# Somewhere else in your script's setup, do something like this
while [[ $# > 0 ]]; do
case "$1" in
-v|--verbose) echoLog='echo'; ;;
esac
shift;
done
Now, you can just drop lines like $echoLog "Doing something verbose log worthy"
anywhere you want.
![tamasgal](https://i.stack.imgur.com/76Iiz.jpg?s=256&g=1)
tamasgal
My name is Tamás Gál, I am an astroparticle physicist and working at Erlangen Centre for Astroparticle Physics (ECAP). I currently develop online monitoring and live reconstruction algorithms for the KM3NeT neutrino telescopes and maintain the IT services of KM3NeT and ECAP. My DevOps engineering skills include Docker (+Swarm), GitLab CI/CD, Jenkins, Xen, OpenVZ, Ansible and more than two decades of experience with Linux and BSD as system administrator. I spend most of my time with science (astroparticle physics), coding (Julia, Python, …) and electronics (both analog/digital); the rest preferably off the road with one of my motorbikes. I have an obsession to repair things and keep them alive as long as possible, no matter if it requires a gearbox restoration of my BMW R1100 GS or replacing a dead 0201 SMD capacitor on a MacBook logicboard. Furthermore, I love making music and spend a lot of time on my DIY modular synthesizer. #SOreadytohelp
Updated on April 10, 2020Comments
-
tamasgal about 4 years
When I write bash scripts I usually get the verbose mode this way (simplified):
_V=0 while getopts "v" OPTION do case $OPTION in v) _V=1 ;; esac done
and then every time I want a "verbose output" I type this:
[ $_V -eq 1 ] && echo "verbose mode on" || echo "verbose mode off"
or for example this:
[ $_V -eq 1 ] && command -v || command
Is there a way to do it more elegant? I was thinking about defining a function named "verbose" and type it instead of
[ $_V -eq 1 ]
, but this would only be a tiny improvement.I'm sure, there is more common way to do it…