Façon élégante pour le mode verbeux dans les scripts?
quand j'écris des scripts bash, j'obtiens habituellement le mode verbose de cette façon (simplifié):
_V=0
while getopts "v" OPTION
do
case $OPTION in
v) _V=1
;;
esac
done
et puis à chaque fois que je veux une "sortie verbeuse" je tape ceci:
[ $_V -eq 1 ] && echo "verbose mode on" || echo "verbose mode off"
ou par exemple comme ceci:
[ $_V -eq 1 ] && command -v || command
Est-il un moyen de le faire plus élégant? Je pensais définir une fonction appelée "verbose" et la taper au lieu de [ $_V -eq 1 ]
, mais cela ne serait qu'une légère amélioration.
j'en suis sûr, il est plus courant de le faire...
9 réponses
Comme vous l'avez remarqué, vous pouvez définir certains log
fonctions log
,log_debug
,log_error
, etc.
function log () {
if [[ $_V -eq 1 ]]; then
echo "$@"
fi
}
il peut aider à augmenter la lisibilité de votre code principal et cacher la logique de show\nonshow dans la fonction de journalisation.
log "some text"
Si _V
(variable globale) est égal 1
"texte" sera imprimé, dans d'autres cas, il ne sera pas.
Après la lecture de tous les autres postes, je suis venu avec cette
# 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=
shift
if [ ${__VERBOSE} -ge ${LEVEL} ]; then
echo "[${LOG_LEVELS[$LEVEL]}]" "$@"
fi
}
Ensuite, vous pouvez simplement l'utiliser comme ceci
# verbose error
.log 3 "Something is wrong here"
Qui aura pour effet de sortie
[error] Something is wrong here
#!/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
Un premier essai à un système plus souple avec les niveaux de verbosité (Bash 4):
# CONFIG SECTION
# verbosity level definitions
config[verb_levels]='debug info status warning error critical fatal'
# verbosity levels that are to be user-selectable (0-this value)
config[verb_override]=3
# user-selected verbosity levels (0=none, 1=warnings, 2=warnings+info, 3=warning+info+debug)
config[verbosity]=2
# FUNCTION DEFINITIONS SECTION
_messages() {
# shortcut functions for messages
# non overridable levels exit with errlevel
# safe eval, it only uses two (namespaced) values, and a few builtins
local verbosity macro level=0
for verbosity in ${config[verb_levels]}; do
IFS="" read -rd'' macro <<MACRO
_$verbosity() {
$( (( $level <= ${config[verb_override]} )) && echo "(( ${config[verbosity]} + $level > ${config[verb_override]} )) &&" ) echo "${verbosity}: $@";
$( (( $level > ${config[verb_override]} )) && echo "exit $(( level - ${config[verb_override]} ));" )
}
MACRO
eval "$macro"
(( level++ ))
done
}
# INITIALIZATION SECTION
_messages
Après l'initialisation, n'importe où dans votre code, vous pouvez utiliser des choses comme:
! (( $# )) && _error "parameter expected"
[[ -f somefile ]] && _warning "file $somefile already exists"
_info "some info"
_status "running command"
if (( ${config[verbosity]} <= 1 )); then
command
else
command -v
fi
# explicitly changing verbosity at run time
old_verbosity=${config[verbosity]}
config[verbosity]=1
etc.
j'ai aussi trouvé cette fonction pour faire un rapide ifelse:
function verbose () {
[[ $_V -eq 1 ]] && return 0 || return 1
}
exécute une commande si $_v est défini à 1. L'utiliser comme ceci:
verbose && command #command will be executed if $_V == 1
ou
verbose && command -v || command # execute 'command -v' if $_V==1, else execute 'command'
si vous voulez éviter de faire une déclaration "si" chaque fois que vous voulez enregistrer quelque chose, vous pouvez essayer cette approche (qui est la façon dont je le fais).
L'idée est qu'au lieu d'appeler log
, vous appelez $echoLog
à la place. Donc, si vous êtes en mode verbose $echoLog
sera echo
, mais en mode non verbeux, c'est une fonction qui n'imprime rien et ignore simplement les arguments.
voici quelques codes que vous pouvez copier.
# 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 "" in
-v|--verbose) echoLog='echo'; ;;
esac
shift;
done
Maintenant, vous pouvez déposer des lignes comme $echoLog "Doing something verbose log worthy"
n'importe où vous voulez.
verbose=false
while getopts "v" OPTION
do
case $OPTION in
v) verbose=true
;;
esac
done
$verbose && echo "Verbose mode on" || echo "Verbose mode off"
ceci exécutera /bin/true
ou /bin/false
, retournant 0 ou 1 respectivement.
pour éviter d'utiliser des déclarations if multiples ou d'utiliser une variable pour tenir un nom de fonction Que diriez-vous de déclarer différentes fonctions basées sur la verbosité!
cela fonctionne pour tous les dérivés bourne shell pas seulement bash!
#verbose=verbose_true # uncomment to make script verbose
if [ "$verbose" ]; then
log() { echo "$@"; }
else
log() { :; }
fi
log This Script is Verbose
NOTE: l'utilisation de "verbose=verbose_true" rend le traçage du script beaucoup plus agréable mais vous pouvez faire que l'on si toutefois vous le souhaitez.
je propose une version modifiée de @fentasréponse:
# 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=
shift
if [ ${__VERBOSE} -ge ${LEVEL} ]; then
if [ -t 0 ]; then
# seems we are in an interactive shell
echo "[${LOG_LEVELS[$LEVEL]}]" "$@" >&2
else
# seems we are in a cron job
logger -p "${LOG_LEVELS[$LEVEL]}" -t "[$$]" -- "$*"
fi
fi
}