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...

22
demandé sur Qantas 94 Heavy 2011-12-10 14:54:16

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.

27
répondu ДМИТРИЙ МАЛИКОВ 2011-12-10 14:42:22

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
16
répondu fentas 2015-11-08 18:48:07
#!/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
6
répondu Petrucci 2014-01-06 02:32:29

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.

2
répondu ata 2011-12-10 16:06:13

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'
2
répondu tamasgal 2013-03-18 15:24:35

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.

2
répondu Ben 2014-09-22 22:50:12
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.

1
répondu user123444555621 2011-12-10 15:13:59

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.

0
répondu anthony 2016-11-15 05:03:53

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
}
0
répondu fraff 2017-10-04 08:16:53