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

Har*_*ald 4 bash debugging function tracing

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

我想定义logs()并且log()至少他们的内容,最多甚至他们的呼叫被禁止set -x输出。

Jef*_*ler 5

你不能改变从函数内部调用函数的方式,但你可以定义函数来调用一个子shell,然后立即关闭跟踪;注意身体周围的括号而不是典型的大括号:

log() (
  set +x
  # rest of log()
)
Run Code Online (Sandbox Code Playgroud)

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

  • 你确定吗?该函数被定义为在子 shell(第二组括号)中运行,因此那里的本地设置会随该 shell 一起消失。 (2认同)

小智 3

一个应该在所有 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"
}
Run Code Online (Sandbox Code Playgroud)

(当然,您可以放弃奇怪的格式+缩进,使其完全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
Run Code Online (Sandbox Code Playgroud)

将导致:

(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
Run Code Online (Sandbox Code Playgroud)