在 bash 脚本中,我有一个log()
在多个地方使用的函数,以及一个logs()
将大量行转移到log()
.当我使用 运行脚本的一部分时,显然和set -x
中的所有命令也会被跟踪。logs()
log()
我想定义logs()
并且log()
至少它们的内容,最多甚至它们的调用都被从set -x
输出中抑制。
答案1
您无法更改从函数内部调用函数的方式,但您可以定义函数来调用子 shell,然后该子 shell 立即关闭跟踪;请注意主体周围的括号而不是典型的大括号:
log() (
set +x
# rest of log()
)
然后,调用log()
仅生成调用本身(来自现有set -x
代码)和set +x
调用,而不生成函数中的其余后续命令。set -x
该功能退出后将恢复现有设置。
答案2
一个应该在所有 shell 中都有效的快速而肮脏的技巧是(暂时)使您的log
外部脚本而不是函数。
在 bash 中,您还可以使用trap '...' DEBUG
和shopt -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
答案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() 的每个调用,而不是在函数内部。