定义在 xtrace 中不显示的 bash 函数(set -x)

定义在 xtrace 中不显示的 bash 函数(set -x)

在 bash 脚本中,我有一个log()在多个地方使用的函数,以及一个logs()将大量行转移到log().当我使用 运行脚本的一部分时,显然和set -x中的所有命令也会被跟踪。logs()log()

我想定义logs()并且log()至少它们的内容,最多甚至它们的调用都被从set -x输出中抑制。

答案1

您无法更改从函数内部调用函数的方式,但您可以定义函数来调用子 shell,然后该子 shell 立即关闭跟踪;请注意主体周围的括号而不是典型的大括号:

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

然后,调用log()仅生成调用本身(来自现有set -x代码)和set +x调用,而不生成函数中的其余后续命令。set -x该功能退出后将恢复现有设置。

答案2

一个应该在所有 shell 中都有效的快速而肮脏的技巧是(暂时)使您的log外部脚本而不是函数。

在 bash 中,您还可以使用trap '...' DEBUGshopt -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() 的每个调用,而不是在函数内部。

相关内容