web-dev-qa-db-fra.com

Manière élégante pour le mode prolixe dans des scripts?

Quand j'écris des scripts bash, j'obtiens généralement le mode commenté (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 prolixe" je tape ceci:

[ $_V -eq 1 ] && echo "verbose mode on" || echo "verbose mode off"

ou par exemple ceci:

[ $_V -eq 1 ] && command -v || command

Y a-t-il un moyen de le faire plus élégant? Je pensais définir une fonction nommée "verbose" et la taper à la place de [ $_V -eq 1 ], mais ce ne serait qu'une infime amélioration.

Je suis sûr qu'il y a une manière plus commune de le faire…

23
tamasgal

Comme vous l'avez remarqué, vous pouvez définir des fonctions log telles que log, log_debug, log_error, etc.

function log () {
    if [[ $_V -eq 1 ]]; then
        echo "$@"
    fi
}

Cela peut aider à augmenter la lisibilité de votre code principal et à masquer la logique show\nonshow dans la fonction de journalisation.

log "some text"

Si _V (variable globale) est égal à 1 "du texte" sera imprimé, sinon ce ne sera pas le cas.

Après avoir lu tous les autres posts, je suis venu avec ce

# 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
}

Ensuite, vous pouvez simplement l'utiliser comme ça

# verbose error
.log 3 "Something is wrong here"

Qui va sortir

[error] Something is wrong here
15
fentas
#!/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
5
Petrucci

Un premier essai avec un système plus flexible avec des 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 éléments tels que:

! (( $# )) && _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.

1
ata

Je suis également venu avec cette fonction pour faire un rapide ifelse:

function verbose () {
    [[ $_V -eq 1 ]] && return 0 || return 1
}

Ceci exécute une commande si $ _V a la valeur 1. Utilisez-le 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'
1
tamasgal

Si vous voulez éviter de faire une déclaration "if" à chaque fois que vous voulez enregistrer quelque chose, vous pouvez essayer cette approche (c'est comment je le fais).

L'idée est qu'au lieu d'appeler log, vous appelez plutôt $echoLog. Donc, si vous êtes en mode verbeux, $echoLog sera simplement echo, mais en mode non-verbose, il s’agira d’une fonction qui n’affiche rien et ignore les arguments. 

Voici du code 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 "$1" in
        -v|--verbose) echoLog='echo'; ;;
    esac
    shift;
done

Maintenant, vous pouvez simplement supprimer des lignes comme $echoLog "Doing something verbose log worthy" où vous voulez.

1
Ben
verbose=false

while getopts "v" OPTION
do
  case $OPTION in
    v) verbose=true
       ;;
  esac
done

Ensuite

$verbose && echo "Verbose mode on" || echo "Verbose mode off"

Ceci exécutera /bin/true ou /bin/false, renvoyant 0 ou 1 respectivement.

0
user123444555621

Pour éviter d'utiliser plusieurs instructions if ou d'utiliser une variable pour conserver un nom de fonction, pourquoi ne pas déclarer différentes fonctions en fonction de 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 de script beaucoup plus agréable Mais vous pouvez le créer si vous le souhaitez.

0
anthony