当我还为详细模式设置了详细时,我正在尝试配置 PS4 以获得更好的 xtrace 输出。我想做的几件事会产生子shell,但我想查看这些操作的任何 -x 或 -v 输出,因为它们会为每一行打印。
我还想摆脱嵌套/间接深度级别指示器 (+),因为我希望跟踪输出对齐。
我最初的想法是:
BACKSPACES=$'\b\b\b\b\b\b\b\b'
PS4='+`printf "%s[\t] %-16.16s:%03d (%-16.16s) $ " ${BACKSPACES:0:$BASH_SUBSHELL} $(basename $BASH_SOURCE) $LINENO ${FUNCNAME[0]:+${FUNCNAME[0]}}`'
我遇到的第一个问题是 $BASH_SUBSHELL 似乎并不总是与要打印的 + 的数量相同。调查 $SHLVL 也无济于事。
echo $X
+ 0 2 $ echo x <-- toplevel prints one + and $BASH_SUBSHELL is 0, as expected
x
( echo subshell )
+ 1 2 $ echo subshell <-- $BASH_SUBSHELL increments to 1 as expected, but why only one + instead of two ++?
source ./test2.sh
+ 0 2 $ source ./test2.sh
echo $X$X$X$X
++ 0 2 $ echo xxxx <-- ??? is $BASH_SUBSHELL relative to the current file or something but the + indicators are not???
xxxx
subshell
我想我已经通过忘记使用 $BASH_SUBSHELL 而是将 PS4 中的第一个字符设置为不可打印的字符来解决这个问题,但我仍然想知道为什么 $BASH_SUBSHELL 不是我所期望的。
为了解决在 PS4 中创建子 shell 的问题,我查看了与 PS1 的 PROMPT_COMMAND 等效的内容,但除了一些关于如何自己实现它的指示外,没有找到任何东西。
我认为我发现的最好方法是捕获 DEBUG 信号。
trap 'debugfun $BASH_SOURCE' DEBUG
当然,-vx 选项也适用于对 debugfun 的调用。我抑制该输出的解决方案是将函数的步骤包含在 set +vx 和 set -vx 中。
debugfun() {
set +vx
VAR=`basename $1 .sh`
set -vx
}
现在......我不得不处理每个呼叫打印的问题:
debugfun $BASH_SOURCE <-- from -v
++ debugfun ./test.sh <-- from -x
++ set +vx <-- from -x
我不确定为什么 -v 也不会在“set +vx”行上打印。我认为 -T 选项可能会这样做,但事实并非如此。
无论如何,我认为输出总是一致的,所以我所要做的就是从 debugfun 中删除这 3 行。我丑陋的解决方案是在“set +vx”之后添加这一行:
printf "\b\r\033[K\b\r\033[K\b\r\033[K" # clear previous 3 lines
有效!
...除非我不止一次管道。
我将删除 printf 行以说明原因:
echo $X$X | sed 's/x/y/' # pipe once... debugfun is called every time before each pipe component
debugfun $BASH_SOURCE
++ debugfun ./test.sh
++ set +vx
debugfun $BASH_SOURCE
++ debugfun ./test.sh
++ set +vx
+ echo xx
+ sed s/x/y/
echo $X$X$X | sed 's/x/y/' | sed 's/y/x/' # pipe twice
debugfun $BASH_SOURCE
++ debugfun ./test.sh
++ set +vx
debugfun $BASH_SOURCE
++ debugfun ./test.sh
++ set +vx
+ echo xxx
+ sed s/x/y/ # because this line is here, clearing 3 previous lines from the next "set +vx" would clear it
debugfun $BASH_SOURCE
++ debugfun ./test.sh
++ set +vx
+ sed s/y/x/
xxx
最后,我确实提出了这个解决方案,但我认为它真的很难看,而且虽然很接近,但并不是我想要的:
SPACES=" "
PS4='^@\[\e[31m\]+ [\t] \
${SPACES:0:$((${#BASH_SOURCE} > 24 ? 0 : 24 - ${#BASH_SOURCE}))}${BASH_SOURCE:$((${#BASH_SOURCE} < 24 ? 0 : -24))}:\
${SPACES:0:$((3-${#LINENO}))}$LINENO \
${FUNCNAME:-${SPACES:0:20}}${FUNCNAME:+${SPACES:0:$((20 - ${#FUNCNAME}))}} \
$ \[\e[0m\]'
我不喜欢的主要事情是我不能嵌套 bash 字符串操作,不仅可以反向截断 $BASH_SOURCE,还可以在没有子 shell 的情况下获取它的基本名称(即与 echo ${BASH_SOURCE##*/} 结合)
我没有想法,希望对如何完成我正在尝试做的事情进行澄清和提示。
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)