Logging bash scripts with verbose and xxtrace (set -vx) and configuring PS4

I am trying to tweak PS4 for better xxtrace output when I also have a verbose set for verbose mode. Some of the things I would like to do is wait, but I want to see any -x or -v output for these operations because they will print for every line.

I also wanted to get rid of the depth gauge / depth gauge (+) because I want the tracing result to be aligned.

My initial idea:

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]}}`'

      

The first problem I ran into was that $ BASH_SUBSHELL doesn't always match the + number that will be printed. Searching $ SHLVL didn't help either.

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

      

I think I got around this by forgetting about using $ BASH_SUBSHELL and making the first character in PS4 obscene instead, but I would still like to know why $ BASH_SUBSHELL is not what I expect.

To work around the issue with PS4-generated subshells, I looked at the PS1 equivalent PROMPT_COMMAND but couldn't find anything other than some pointers on how to implement it myself.

The best way I thought I found was to grab the DEBUG signal.

trap 'debugfun $BASH_SOURCE' DEBUG

      

Of course, the -vx options also apply to debugfun calls. My solution to suppress this output was to wrap the function steps in the + vx set and set the -vx.

debugfun() {
  set +vx
  VAR=`basename $1 .sh`
  set -vx
}

      

Now ... I had to deal with a question about every print call:

debugfun $BASH_SOURCE <-- from -v
++ debugfun ./test.sh <-- from -x
++ set +vx <-- from -x

      

I'm not sure why -v doesn't print on the "set + vx" line. I thought the -T option could do it, but it doesn't.

Anyway, I thought the output would always be consistent, so all I had to do was erase those 3 lines from debugfun. My ugly solution was to add this line after "set + vx":

printf "\b\r\033[K\b\r\033[K\b\r\033[K" # clear previous 3 lines

      

It worked!

... Except when I connect multiple times.

I'll remove the printf line to show why:

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

      

I finally came up with this solution, but I think it is really ugly and, although close, not quite what I want:

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\]'

      

The main thing I don't like is that I can't nest bash string manipulations to not only undo the truncation of $ BASH_SOURCE, but also get its basename without a subshell (i.e. concatenate with echo $ {BASH_SOURCE ## * /} )

I have no ideas and I will be grateful and clarified as well as advice on doing what I am trying to do.

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

      

+3


source to share


1 answer


I suggest ditching PS4 and making all trace output in DEBUG trap. Most, if not all of these -x fingerprints are available elsewhere. See BASH_SOURCE, BASH_LINENO, FUNCNAME, and BASH_COMMAND.

Like this:



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

set -o functrace
shopt -s extdebug
trap trace DEBUG

      

+3


source







All Articles