使用详细和xtrace(set -vx)记录bash脚本并自定义PS4

时间:2013-02-01 03:14:28

标签: bash debugging shell

我正在尝试配置PS4以获得更好的xtrace输出,当我还为详细模式设置了详细信息时。我想做的几件事会产生子壳,但是我希望看到这些操作的任何-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的情况下获取它的basename(即与echo $ {BASH_SOURCE ## * /结合使用) })

我没有想法,会对如何完成我想要做的事情表示赞赏,澄清或提示。

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

1 个答案:

答案 0 :(得分:3)

我建议放弃PS4并在DEBUG陷阱中执行所有跟踪输出。大多数,如果 并非所有信息-x打印在其他地方都可用。见BASH_SOURCE, BASH_LINENO,FUNCNAME和BASH_COMMAND。

像这样:

function trace()
{
    echo "TRACE" \
         "${BASH_SOURCE[1]}:${BASH_LINENO[0]}:${FUNCNAME[1]}:" \
         "$BASH_COMMAND"
}

set -o functrace
shopt -s extdebug
trap trace DEBUG