web-dev-qa-db-ja.com

xtraceに表示されないbash関数を定義します(-xを設定します)

Bashスクリプトには、いくつかの場所で使用されるlog()関数と、多くの行をlogs()に転送するlog()関数があります。スクリプトの一部を_set -x_で実行すると、明らかにlogs()およびlog()内のすべてのコマンドもトレースされます。

logs()log()を定義して、少なくともそれらのコンテンツ、せいぜいそれらの呼び出しでさえ_set -x_出力から抑制されるようにしたいと思います。

4
Harald

すべてのシェルで機能するはずの迅速で汚いハックは、(一時的に)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
1
mosvy

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

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

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

5
Jeff Schaller

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()の各呼び出しを同様のコードで囲むことができます。

0
wef