Defina a função bash que não aparece no xtrace (set -x)

Defina a função bash que não aparece no xtrace (set -x)

Em um script bash eu tenho uma log()função que é usada em vários lugares, bem como uma logs()função que desvia muita linha para log(). Quando executo partes do script com set -x, obviamente todos os comandos dentro de logs()e log()também são rastreados.

Eu gostaria de definir logs()e log()de forma que pelo menos seu conteúdo, na melhor das hipóteses até mesmo sua chamada, seja suprimida da set -xsaída.

Responder1

Você não pode alterar como a função é chamada de dentro da função, mas pode definir a função para invocar um subshell que desativa imediatamente o rastreamento; observe os parênteses ao redor do corpo em vez dos colchetes típicos:

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

A invocação log()gera apenas a própria chamada (do set -xcódigo existente) e a set +xchamada, e não o restante dos comandos subsequentes na função. A configuração existente set -xé restaurada assim que a função é encerrada.

Responder2

Um hack rápido e sujo que deve funcionar em todos os shells é (temporariamente) tornar seu logscript externo em vez de uma função.

No bash você também pode usar a combinação trap '...' DEBUGand shopt -s extdebug, que é muito mais versátil que set -x. Exemplo:

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

(Claro, você pode dispensar o formato estranho + recuo e torná-lo completamente set-xsemelhante a -; você também pode redirecioná-lo para outro arquivo em vez de misturá-lo com o stderr dos comandos.)

Então:

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

vai resultar em:

(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

Responder3

Para suprimir a saída do xtrace, basta usar set -x. Para ligá-lo novamente, use set -x. Para detectar se está ativado, use shopt -q -o xtrace. por exemplo

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
}

Ainda há alguma 'conversa', mas é o melhor que posso fazer. Para suprimir a visualização das chamadas para log() você pode cercar cada chamada para log() com um código semelhante em vez de dentro da função.

informação relacionada