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

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

bash スクリプトには、log()複数の場所で使用される関数と、logs()多くの行を に転送する関数がありますlog()。 を含むスクリプトの一部を実行すると、当然のことながら、 とset -x内のすべてのコマンドもトレースされます。logs()log()

少なくともその内容、最良の場合はその呼び出しさえも出力から抑制されるように、 とlogs()を定義したいと思います。log()set -x

答え1

関数内から関数の呼び出し方法を変更することはできませんが、関数を定義してサブシェルを呼び出すことで、すぐにトレースをオフにすることができます。通常の中括弧ではなく、本体を囲む括弧に注意してください。

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

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

答え2

すべてのシェルで機能する簡単なハックは、関数logではなく外部スクリプトを(一時的に)作成することです。

bash では、 よりもはるかに汎用性の高いtrap '...' DEBUGと の組み合わせを使用することもできます。例: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() の各呼び出しを囲みます。

関連情報