Bash

定義未出現在 xtrace 中的 bash 函式(set -x)

  • January 19, 2019

在 bash 腳本中,我有一個log()在多個地方使用的函式,以及一個logs()將大量行轉移到log(). 當我使用 執行部分腳本時set -x,顯然logs()和中的所有命令log()也會被跟踪。

我想定義logs()log()至少他們的內容,充其量甚至他們的呼叫都被從set -x輸出中抑制。

應該適用於所有 shell 的快速而骯髒的 hack 是(暫時)使您log的外部腳本而不是函式。

在 bash 中,您還可以使用 a trap '...' DEBUGandshopt -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

您無法更改從函式內部呼叫函式的方式,但您可以定義函式以呼叫子shell,然後立即關閉跟踪;注意主體周圍的括號而不是典型的大括號:

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

然後呼叫log()僅生成呼叫本身(來自現有set -x程式碼)和set +x呼叫,而不是函式中的其餘後續命令。一旦函式退出,現有set -x設置就會恢復。

引用自:https://unix.stackexchange.com/questions/495291