write scripts script read first create bash verbosity

bash - read - ¿Manera elegante para el modo detallado en los scripts?



scripts on linux (9)

Como notó, puede definir algunas funciones de log como log , log_debug , log_error , etc.

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

Puede ayudar a aumentar la legibilidad del código principal y ocultar la función show / nonshow logic into logging.

log "some text"

Si _V (variable global) es igual a 1 , se imprimirá "algún texto", en otro caso no lo será.

Cuando escribo scripts de bash, normalmente obtengo el modo detallado de esta manera (simplificado):

_V=0 while getopts "v" OPTION do case $OPTION in v) _V=1 ;; esac done

y luego cada vez que quiero una "salida detallada" escribo esto:

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

o por ejemplo esto:

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

¿Hay alguna manera de hacerlo más elegante? Estaba pensando en definir una función llamada "verbose" y escribirla en lugar de [ $_V -eq 1 ] , pero esto solo sería una pequeña mejora.

Estoy seguro, hay una forma más común de hacerlo ...


Después de leer todas las otras publicaciones se me ocurrió esto

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

Entonces simplemente puedes usarlo así

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

Que saldrá

[error] Something is wrong here


Para evitar el uso de varias declaraciones if o el uso de una variable para mantener un nombre de función, ¿qué hay de declarar diferentes funciones basadas en la verbosidad?

¡Esto funciona para TODOS los derivados de la concha de bourne, no solo bash!

#verbose=verbose_true # uncomment to make script verbose if [ "$verbose" ]; then log() { echo "$@"; } else log() { :; } fi log This Script is Verbose

NOTA: el uso de "verbose = verbose_true" hace que el seguimiento del script sea mucho más agradable, pero puede hacerlo si lo desea.


Propondría una versión modificada de la @fentas de @fentas :

# 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 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 "$0[$$]" -- "$*" fi fi }


Si desea evitar hacer una declaración "si" cada vez que quiera registrar algo, puede probar este enfoque (que es como lo hago).

La idea es que en lugar de llamar al log , llame a $echoLog en $echoLog lugar. Por lo tanto, si está en modo detallado, $echoLog solo será echo , pero en modo no detallado, es una función que no imprime nada y simplemente ignora los argumentos.

Aquí hay un código que puedes copiar.

# 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

Ahora, solo puede colocar líneas como $echoLog "Doing something verbose log worthy" cualquier lugar que desee.


También se me ocurrió esta función para hacer un rápido ifelse:

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

Esto ejecuta un comando si $ _V se establece en 1. Úselo así:

verbose && command #command will be executed if $_V == 1

o

verbose && command -v || command # execute ''command -v'' if $_V==1, else execute ''command''


Un primer intento en un sistema más flexible con niveles de verbosidad (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

Después de la inicialización, en cualquier parte de tu código puedes usar cosas como:

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


#!/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


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

Entonces

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

Esto ejecutará /bin/true o /bin/false , devolviendo 0 o 1 respectivamente.