Direct xtrace output elsewhere than stderr in zsh
As of zsh 5.7, the answer is no. The trace output always goes to stderr.
Source: reading the source. The trace output is written to the file xtrerr
, which looks promising, but the only assignments to xtrerr
are to stderr
, to a copy of it, or to NULL
.
It should be possible to write a dynamically loadable module that sets xtrerr
, but writing a module outside the zsh source tree is not easy.
A possible workaround is to emulate xtrace
with a DEBUG
trap. This provides the same basic information in most cases, but I'm sure there are plenty of corner cases where xtrace
would be hard or impossible to emulate perfectly. One difference is that the inheritance of the xtrace
option and the inheritance of traps follow different rules in some circumstances related to functions, subshells, emulate
, etc. Proof-of-concept:
trap 'print -r -- "+$0:$LINENO>$ZSH_DEBUG_CMD" >>trace_file' DEBUG
Or maybe a bit more sophisticated (untested):
zmodload zsh/system
sysopen -a -o create -u xtrace_fd trace_file
trap 'syswrite -o $xtrace_fd "+$0:$LINENO>$ZSH_DEBUG_CMD"' DEBUG
I'm using a very simple workaround which may be useful if you want to debug only a specific function although the same idea can be applied to complete tracing with set -x
:
When I need to debug a specific function, say myfunc
, I open a child shell with TRACE_FUNC=myfunc zsh -l 2> debug.err.txt
while I have set in my ~/.zshrc
something along the lines of:
if [ -n "${TRACE_FUNC}" ]; then
functions -t "$TRACE_FUNC"
fi
You can apply the same idea by putting in your ~/.zshrc
the following:
if [ -n "${TRACE_ZSH}" ]; then
set -x
fi
And spawn the child shell with TRACE_ZSH=1 zsh -l 2> debug.err.txt
.