Defina la función bash que no aparece en xtrace (set -x)

Defina la función bash que no aparece en xtrace (set -x)

En un script bash tengo una log()función que se usa en varios lugares, así como una logs()función que desvía muchas líneas a log(). Cuando ejecuto partes del script con set -x, obviamente todos los comandos dentro de logs()y log()también se rastrean.

Me gustaría definir logs()y log()de tal manera que al menos su contenido, en el mejor de los casos incluso su llamada, se suprima de set -xla salida.

Respuesta1

No puede cambiar cómo se invoca la función desde dentro de la función, pero puede definir la función para que invoque una subcapa que luego desactive inmediatamente el seguimiento; observe el paréntesis que rodea el cuerpo en lugar de las típicas llaves:

log() (
  set +x
  # rest of log()
)

Luego , la invocación log()genera solo la llamada en sí (a partir del set -xcódigo existente) y la set +xllamada, no el resto de los comandos posteriores en la función. La configuración existente set -xse restaura una vez que sale la función.

Respuesta2

Un truco rápido y sucio que debería funcionar en todos los shells es convertir (temporalmente) logun script externo en lugar de una función.

En bash también puedes usar una combinación trap '...' DEBUGy shopt -s extdebug, que es mucho más versátil que set -x. Ejemplo:

debug() {
        local f=${FUNCNAME[1]} d=${#FUNCNAME[@]} c=$BASH_COMMAND
        if [ "$NOTRACE" ]; then
                case $debug_skip in ''|$d) debug_skip=;; *) return;; esac
                eval "case \$c in $NOTRACE) debug_skip=\$d; return; esac"
        fi

        # before the 1st command in a function XXX
        case $c in $f|"$f "*) return;; esac

        printf >&2 "%*s(%s) %s\n" $((d * 2 - 4)) "" "$f" "$c"
}

(Por supuesto, puede prescindir del formato extraño + sangría y hacerlo completamente set-xsimilar; también puede redirigirlo a otro archivo en lugar de mezclarlo con los comandos stderr from).

Entonces:

NOTRACE='"log "*'
shopt -s extdebug
trap debug DEBUG

log(){ log1 "$@"; }; log1(){ log2 "$@"; }
log2(){ log3 "$@"; }; log3(){ echo "$@"; }

foo(){ foo1 "$@"; }; foo1(){ foo2 "$@"; }
foo2(){ foo3 "$@"; }; foo3(){ echo "$@"; }

bar(){ case $# in 0) ;; *) echo "$1"; shift; bar "$@";; esac; }

foo 1 2 3
log 7 8 9
bar 1 2 3 4

resultará en:

(main) foo 1 2 3
  (foo) foo1 "$@"
    (foo1) foo2 "$@"
      (foo2) foo3 "$@"
        (foo3) echo "$@"
1 2 3
7 8 9
(main) bar 1 2 3 4
  (bar) case $# in
  (bar) echo "$1"
1
  (bar) shift
    (bar) case $# in
    (bar) echo "$1"
2
    (bar) shift
      (bar) case $# in
      (bar) echo "$1"
3
      (bar) shift
        (bar) case $# in
        (bar) echo "$1"
4
        (bar) shift
          (bar) case $# in

Respuesta3

Para suprimir la salida de xtrace, simplemente use set -x. Para volver a encenderlo, utilice set -x. Para detectar si está encendido, use shopt -q -o xtrace. p.ej

log() {
  if shopt -q -o xtrace; then TRACE_IS_ON=yes; else TRACE_IS_ON=no; fi
  set +x # turn xtrace off
  ...
  [[ "$TRACE_IS_ON" == "yes" ]] && set +x
}

Todavía hay algunas "charlas", pero eso es lo mejor que puedo hacer. Para evitar ver las llamadas a log(), puede rodear cada llamada a log() con un código similar en lugar de hacerlo dentro de la función.

información relacionada