Определите функцию bash, которая не отображается в xtrace (set -x)

Определите функцию bash, которая не отображается в xtrace (set -x)

В скрипте bash у меня есть log()функция, которая используется в нескольких местах, а также logs()функция, которая перенаправляет много строк в log(). Когда я запускаю части скрипта с помощью set -x, очевидно, что все команды внутри logs()и log()также трассируются.

Я хотел бы определить logs()и log()так, чтобы по крайней мере их содержание, в лучшем случае даже их призыв, были подавлены из set -xвывода.

решение1

Изменить способ вызова функции изнутри функции нельзя, но можно определить функцию для вызова подоболочки, которая затем немедленно отключает трассировку; обратите внимание на круглые скобки, окружающие тело, вместо обычных фигурных скобок:

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

Вызов log()затем генерирует только сам вызов (из существующего set -xкода) и set +xвызов, а не остальные последующие команды в функции. Существующая set -xнастройка восстанавливается после выхода из функции.

решение2

Быстрый и грязный прием, который должен работать во всех оболочках, — это (временно) сделать ваш logскрипт внешним, а не функцией.

В bash вы также можете использовать комбинацию trap '...' DEBUGи shopt -s extdebug, которая гораздо более универсальна, чем set -x. Пример:

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

(Конечно, вы можете обойтись без странного формата + отступов и сделать его полностью set-x-подобным; вы также можете перенаправить его в другой файл, а не смешивать со stderr от команд.)

Затем:

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

приведет к:

(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

решение3

Чтобы отключить вывод xtrace, просто используйте set -x. Чтобы включить его снова, используйте set -x. Чтобы определить, включен ли он, используйте shopt -q -o xtrace. например

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
}

Все еще есть некоторая «болтовня», но это лучшее, что я могу сделать. Чтобы подавить просмотр вызовов log(), вы можете окружить каждый вызов log() похожим кодом, а не внутри функции.

Связанный контент