Colodebug: a simple way to improve Bash script debugging
johannes.truschnigg.info
johannes.truschnigg.info
major: it does not work on POSIX shells, because ':' is not a valid function name and
minor: the function itself should be changed to use the builtin 'case' instead of the bashims [[ ... ]]
Problem #1 (at least for the "advanced" part of the article's suggestion) is unfixable unless you boil the ocean and change the POSIX spec. I tried to make that clear in the prose, but might have failed at it. It's also the reason why I chose the title to refer to `bash` scripts in particular.
Problem #2 becomes less relevant once you realize that problem #1 completely overshadows it. And in `zsh`, where you can also redefine `:` to invoke a custom function, tests via `[[` also work just like they do in bash.
#!/bin/sh
alias :=mydebug
mydebug() { printf '%s\n' "$\*"; }
foo=1
: this is a debugable comment
bar=2Would it be OK for you if I added that information/workaround to the article (crediting you, of course)?
"Stick to portable constructs where possible, and
you will make somebody's life easier in the future.
Maybe your own."It prompted me to mention BashSupport Pro which I installed a couple of months back.
It's a plugin for JetBrains IDEs that allows step debugging and variable inspection for Bash scripts in the same way as other supported languages.
$cat z
#!/bin/bash
set -u # fail if unset variable is used
if [[ -n ${COLODEBUG} && ${-} != *x* ]]
then
:() {
[[ ${1:--} != ::* ]] && return 0
printf '%s\n' "${*}" >&2
}
fi
echo hello
$./z
./z: line 10: COLODEBUG: unbound variable
$
The -n test should look like this: if [[ -n ${COLODEBUG:-} && ${-} != *x* ]]It's kinda unfortunate this slipped through, because before I tried to "formalize" this little trick in the article yesterday, I definitely remember having used variants that guarded against this little nasty trap you now independently rediscovered ;)
Would you mind me updating the article accordingly, and crediting your HN account name/profile in the changelog?
Thanks a lot for your rigorous reading and very constructive feedback! :)
No problem. I'm retired now so my name doesn't appear in changelogs as often as it used to!
The first suggestion is to add
export -f :
just before the fi so that it is available to scripts called from the main script.The second is to add
local IFS=" " # Insulate : from changes to IFS
before the printf.because if I didn't then each word of the comment would appear on a separate line like this:
::
a
b
c
instead of this: :: a b c
the reason for this is that I had defined IFS="/n/t"
as suggested by the Unofficial Strict Mode.Here's how I do the equivalent with a POSIX function to print a message to STDOUT:
out() { printf %s\\n "$*" }