xtrace に表示されない bash 関数の定義 (set -x)

xtrace に表示されない bash 関数の定義 (set -x)

bashスクリプトには、log()複数の場所で使用される関数とlogs()多数の行をlog()set -xlogs()log()

私は定義logs()し、log()少なくともその内容とせいぜい呼び出しまでもset -x出力から抑制したいと思います。

答え1

関数内で関数が呼び出される方法を変更することはできませんが、サブシェルを呼び出す関数を定義できます。これにより、通常の中括弧の代わりに本文の周りに括弧が表示されます。

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

その後、呼び出しは関数の残りの後続のコマンドではなく、呼び出しlog()自体(既存のset -xコードから)と呼び出しのみを生成します。この機能を終了すると、既存の設定が復元されます。set +xset -x

答え2

すべてのシェルで動作する必要がある迅速で汚い方法は、関数ではlogなく外部スクリプトを(一時的に)作成することです。

trap '...' DEBUGBashではを使用して結合することもできますshopt -s extdebugset -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() 呼び出しを囲むことができます。

関連情報