Is it safe to eval $BASH_COMMAND?
One possibility is to make a wrapper function that will at the same time print the command and execute it, as follows:
debug() {
# This function prints (to stdout) its arguments and executes them
local args=() idx=0 IFS=' ' c
for c; do printf -v args[idx++] '%q' "$c"; done
printf "%s\n" "${args[*]}"
# Execute!
"$@"
}
So that in your script you can do:
debug echo "$ARG"
No need to fiddle with the trap. The drawback is that it adds some debug
keywords all over your code (but that should be fine, it's common to have such stuff, like asserts, etc.).
You can even add a global variable DEBUG
and modify the debug
function like so:
debug() {
# This function prints (to stdout) its arguments if DEBUG is non-null
# and executes them
if [[ $DEBUG ]]; then
local args=() idx=0 IFS=' ' c
for c; do printf -v args[idx++] '%q' "$c"; done
printf "%s\n" "${args[*]}"
fi
# Execute!
"$@"
}
Then you can call your script as:
$ DEBUG=yes ./myscript
or
$ DEBUG= ./myscript
or just
$ ./myscript
depending whether you want to have the debug info or not.
I capitalized the DEBUG
variable because it should be treated as an environment variable. DEBUG
is a trivial and common name, so this might clash with other commands. Maybe call it GNIOURF_DEBUG
or MARTIN_VON_WITTICH_DEBUG
or UNICORN_DEBUG
if you like unicorns (and then you probably like ponies too).
Note. In the debug
function, I carefully formatted each argument with printf '%q'
so that the output will be correctly escaped and quoted so as to be reusable verbatim with a direct copy and paste. It will also show you exactly what the shell saw as you'll be able to figure out each argument (in case of spaces or other funny symbols). This function also uses direct assignment with the -v
switch of printf
so as to avoid unnecessary subshells.
eval "$BASH_COMMAND"
runs the command.
printf '%s\n' "$BASH_COMMAND"
prints the exact specified command, plus a newline.
If the command contains variables (i.e. if it's something like cat "$foo"
), then printing out the command prints out the variable text. It is impossible to print the variable's value without executing the command — think of commands like variable=$(some_function) other_variable=$variable
.
The simplest way to get a trace from executing a shell script is to set the xtrace
shell option by running the script as bash -x /path/to/script
or invoking set -x
inside the shell. The trace is printed to standard error.