Trace to a file
Send set -x output to a file with BASH_XTRACEFD so the trace stops mixing with the standard error of the script. It needs Bash 4.1 or later.
The trace of set -x lands on standard error, in between the real error messages, and you want it kept apart.
cat > demo.sh <<'EOF'
#!/bin/bash
exec 9>trace.log
BASH_XTRACEFD=9
set -x
echo "to stdout"
echo "to stderr" >&2
ls /nonexistent
EOF
bash demo.sh 2>errors.txt
echo "--- stderr"; cat errors.txt
echo "--- trace.log"; cat trace.logto stdout
--- stderr
to stderr
ls: cannot access '/nonexistent': No such file or directory
--- trace.log
+ echo 'to stdout'
+ echo 'to stderr'
+ ls /nonexistentWhen BASH_XTRACEFD holds the number of an open file descriptor, Bash writes the trace there rather than to standard error, as the manual states. The stderr file in this run holds only the two messages the script produced itself, and the commands, with their plus prefix, are in trace.log.
Bash closes the descriptor when you unset the variable or assign it another value, so do not reassign it while tracing. Use a descriptor of 9 or lower to be safe with other shells, or a high one if the script uses many. A script running in many processes needs a separate file for each, or the traces interleave.