6
#!/bin/bash -x
echo This is a script that has debugging turned on

This script outputs

+ echo This is a script that has debugging turned on
This is a script that has debugging turned on

I want to get rid of these +'s by deleting them or replacing them. I expected sed could fix my problem (sed 's/^\++//g') -- But this approach doesn't affect the debug output lines.

With some more experimenting, I discovered that the debug output seems to be getting written to stderr (inferred this with the command ./test.sh 2>/dev/null which the output then excludes the debug lines)

With this new information, I would expect this to work ./test.sh 2>&1 | sed 's/^\++//g'

But, alas, I still get the same undesired output:

+ echo This is a script that has debugging turned on
This is a script that has debugging turned on
  • 3
    Why are you working so hard to undo what -x has added? Why not just remove the -x? – Jeff Schaller Oct 23 '18 at 17:58
  • Do you just want to remove the ´ + ´ but keep the line on stderr? – RudiC Oct 23 '18 at 21:34
  • Aside, do not use /bin/bash in your shebang line! Always defer to env: #!/usr/bin/env bash. Unfortunately this approach no longer allows you to pass additional parameters (i.e. -x in this case). – Konrad Rudolph Oct 23 '18 at 22:49
  • As a side note, foo 2>&1 | bar can be written more compactly as foo |& bar – Andrea Corbellini Oct 23 '18 at 23:33
15

The + is the PS4 prompt. Set it to an empty string:

#!/bin/bash

PS4=''
set -x

echo 'This is a script that has debugging turned on'

Testing:

$ bash script.sh
echo 'This is a script that has debugging turned on'
This is a script that has debugging turned on

Or, with your original script, set PS4 to an empty string for the script when invoking it:

$ PS4='' ./script.sh
echo This is a script that has debugging turned on
This is a script that has debugging turned on

This could be used to insert a timestamp:

$ PS4='$(date +"%T: ")' ./script.sh
21:08:19: echo 'This is a script that has debugging turned on'
This is a script that has debugging turned on
21:08:19: echo 'Now sleeping for 2 seconds'
Now sleeping for 2 seconds
21:08:19: sleep 2
21:08:21: echo Done
Done
  • 1
    If you want to avoid the fork & exec during prompt evaluation you can use Bash’s extension to the built-in printf command: $(printf '%(%T)T: ' -1). – David Foerster Oct 24 '18 at 7:01
6

The main limitation you're running into is that + is an extended regular expression feature, so you'll need to enable extended regular expression functionality; with most seds, that's with the -E flag:

./test.sh 2>&1 | sed -E 's/^\++ //'

I made two other changes:

  • added a trailing space, so that debugged commands show up left-aligned
  • removed the /g flag, since the regex is anchored, there can be only one match per line
  • Note that once you commingle stdout and stderr, any actual (stdout) output with leading plus signs will also be stripped. – Jeff Schaller Oct 23 '18 at 18:06
  • Yes. I realize this. With Kusalandanda's answer it will circumvent this problem. Although this discovery that it is coming over standard error is surprising. It may just be that fact rather than the +'s that is causing the root behavior I'm seeing. – aitee Oct 23 '18 at 21:07
5

You can redirect stderr into a process substitution. However that may affect the order of the output:

$ bash -x -c 'hostname; echo "$(date)"'
+ hostname
jackmanVM
++ date
+ echo 'Tue Oct 23 15:22:02 EDT 2018'
Tue Oct 23 15:22:02 EDT 2018

$ bash -x -c 'hostname; echo "$(date)"' 2> >(sed -E 's/^\++/debug: /')
debug:  hostname
jackmanVM
debug:  date
Tue Oct 23 15:22:35 EDT 2018
debug:  echo 'Tue Oct 23 15:22:35 EDT 2018'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.