.png)
In einem Bash-Skript habe ich eine log()
Funktion, die an mehreren Stellen verwendet wird, sowie eine logs()
Funktion, die viele Zeilen nach umleitet log()
. Wenn ich Teile des Skripts mit ausführe set -x
, werden natürlich auch alle Befehle innerhalb von logs()
und log()
verfolgt.
Ich möchte logs()
und log()
so definieren, dass zumindest ihr Inhalt, im besten Fall sogar ihr Aufruf bei set -x
der Ausgabe unterdrückt wird.
Antwort1
Sie können nicht ändern, wie die Funktion innerhalb der Funktion aufgerufen wird. Sie können die Funktion jedoch so definieren, dass eine Untershell aufgerufen wird, die dann die Ablaufverfolgung sofort abschaltet. Beachten Sie die Klammern, die den Textkörper umgeben, anstelle der üblichen geschweiften Klammern:
log() (
set +x
# rest of log()
)
Der Aufruf log()
generiert dann nur den Aufruf selbst (aus dem vorhandenen set -x
Code) und den set +x
Aufruf, nicht den Rest der nachfolgenden Befehle in der Funktion. Die vorhandene set -x
Einstellung wird wiederhergestellt, sobald die Funktion beendet wird.
Antwort2
Ein schneller und einfacher Hack, der in allen Shells funktionieren sollte, besteht darin, Ihr Skript (vorübergehend) zu log
einem externen Skript statt einer Funktion zu machen.
In Bash können Sie auch eine Kombination aus trap '...' DEBUG
und verwenden shopt -s extdebug
, die vielseitiger ist als set -x
. Beispiel:
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"
}
(Natürlich können Sie auf das seltsame Format + Einrückung verzichten und es vollständig set-x
-ähnlich machen; Sie können es auch in eine andere Datei umleiten, anstatt es mit dem stderr von Befehlen zu mischen.)
Dann:
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
wird darin enden, dass:
(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
Antwort3
Um die xtrace-Ausgabe zu unterdrücken, verwenden Sie einfach set -x
. Um sie wieder einzuschalten, verwenden Sie set -x
. Um festzustellen, ob sie eingeschaltet ist, verwenden Sie shopt -q -o xtrace
. zB
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
}
Es gibt immer noch etwas „Geplapper“, aber das ist das Beste, was ich tun kann. Um die Aufrufe von log() nicht sichtbar zu machen, können Sie jeden Aufruf von log() mit einem ähnlichen Code umgeben, anstatt ihn in die Funktion einzufügen.