定義在 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() 的每個調用,而不是在函數內部。

相關內容