好的,我有一个像这样的调试设置:
DVAR=();
function DBG() {
if [[ $1 == -s ]]; then shift; stackTrace; fi;
if [[ ! -z ${DVAR[@]} ]]; then
for _v in ${!DVAR[@]}; do
echo "${DVAR[$_v]}" >> $LOG;
unset DVAR[$_v];
done;
fi
local tmp=("$*")
[[ ! -z $tmp ]]&&echo "$tmp" >> $LOG||continue;
}
每隔一段时间,我要么直接调用,要么直接调用
,我希望更多地采用这种方法,反复向数组中添加内容,稍后再调用它。具体来说,我想使用这个:
DVAR+="${0##*/}${FUNCNAME[0]}:$LINENO === assorted local variables and stuff here ====="
第一部分相当拗口,真的把我的代码弄乱了。我真的很想这样说:
DBG === assorted local variables and stuff here=====
我试着搞乱别名,甚至eval,都没有。evail。嗯
Thoughts anyone?
就像@ufopilot所说的,您应该使用DVAR+=("....")将您的行添加为数组中的新条目,而不是通过将其连接到第一个元素来将其作为长字符串覆盖。下面是解释:
连接:
$ DVAR=()
$ DVAR+="foo"
$ DVAR+="bar"
$ declare -p DVAR
declare -a DVAR=([0]="foobar")
$ echo ${DVAR[@]}
foobar
追加新条目:
$ DVAR=()
$ DVAR+=(foo)
$ DVAR+=(bar)
$ declare -p DVAR
declare -a DVAR=([0]="foo" [1]="bar")
$ echo "${DVAR[@]}"
foo bar
下面是我为了调试而组合在一起的一个函数示例。函数是get_stack,它将从调用它的人那里获得函数名和调用函数所在位置的文件名,以及跟踪,以便您可以看到调用历史。
文件test.sh:
#!/usr/bin/env bash
foo() {
get_stack
echo -e "$stack_trace" # Note the quotation to get indentation
}
get_stack () {
stack_trace=""
local i stack_size=${#FUNCNAME[@]}
local indent=" "
local newline="" # newline only after first line
# Offset to skip get_stack function
for (( i=0; i<$stack_size; i++ )); do
local func="${FUNCNAME[$i]}"
[ x$func = x ] && func=MAIN
local linen="${BASH_LINENO[$(( i - 1 ))]}"
local src="${BASH_SOURCE[$i]}"
[ x"$src" = x ] && src=non_file_source
stack_trace+="${newline}${indent}-> $src [$func]: $linen"
newline="n"
indent="$indent "
done
}
echo "stack from test.sh"
foo
文件test2.sh:
#!/usr/bin/env bash
source test.sh
echo "stack from test2.sh"
foo
输出:
stack from test.sh
-> test.sh [foo]: 4
-> test.sh [source]: 28
-> ./test2.sh [main]: 3
stack from test2.sh
-> test.sh [foo]: 4
-> ./test2.sh [main]: 6
在我的脚本中,我有一个向下的箭头ascii字符,看起来比"->"但不知道如何让stackoverflow正确显示它。ascii码为u21b3。
在堆栈跟踪中可以看到,"foo"运行在源函数,就像它应该做的那样。但是现在很清楚为什么它运行并输出文本!
我认为这很好地演示了数组FUNCNAME如何在调用堆栈中向后走。此外,bash_source本身也是一个数组,具有匹配的索引,但是它将显示函数调用来自哪个文件。修改get_stack"函数检查这些数组:
foo() {
get_stack
echo -e "$stack_trace"
echo "${BASH_SOURCE[@]}"
echo "${FUNCNAME[@]}"
}
收益率:
stack from test.sh
-> test.sh [foo]: 4
-> test.sh [source]: 30
-> ./test2.sh [main]: 3
test.sh test.sh ./test2.sh
foo source main
stack from test2.sh
-> test.sh [foo]: 4
-> ./test2.sh [main]: 6
test.sh ./test2.sh
foo main
可以看到,第一组输出属于test.sh,它来自源代码。这可以在BASH_SOURCE: "foo source main"中看到。"main"是主作用域,这是运行的东西,但不是在函数中,而是在文件的主体中。在本例中,test.sh具有"foo"调用它,该文件将运行。
我希望你看到索引属于同一个调用,但产生不同的信息。
现在,对于您来说,您只想一次又一次地添加字符串,而不是整个same-y信息。因为我不确定您是否需要堆栈跟踪,所以我只是将消息字符串添加到第一个调用函数实例中。我还修正了一些旧代码,使它更好一些。
带消息的新改进函数:
get_stack () {
local msg="$@"
stack_trace=""
local i stack_size=${#FUNCNAME[@]}
local indent=" "
# Offset to skip get_stack function
for (( i=1; i<$stack_size; i++ )); do
local func="${FUNCNAME[$i]}"
[ x$func = x ] && func=MAIN
local linen="${BASH_LINENO[$(( i - 1 ))]}"
local src="${BASH_SOURCE[$i]}"
[ x"$src" = x ] && src=non_file_source
stack_trace+="${newline:=n}${indent}-> $src [$func:$linen]${msg:+": $msg"}"
msg=""
indent="$indent "
done
}
输出:
$ ./test2.sh
stack from test.sh
-> test.sh [foo:4]: my message
-> test.sh [source:28]
-> ./test2.sh [main:3]
stack from test2.sh
-> test.sh [foo:4]: my message
-> ./test2.sh [main:6]
注意${var:=X}将初始化"var"与"X"如果var未初始化或设置为空字符串,则${var:+X}将替换"var"与"X"如果var被初始化/设置为非空字符串,最后作为奖励,${var:-X}将替换"var"与"X"如果var未初始化/设置为空字符串。这是bash中的变量替换,非常方便!
有一些片段你可以剪切和传递到你的函数中,或者如果你需要一个基于堆栈的日志,你可以使用我的函数作为基础。
希望这对你的努力有帮助!