Skip to content
shellhacks.dev
Debugging

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.

1 min read
Summarize in AI

The trace of set -x lands on standard error, in between the real error messages, and you want it kept apart.

Shell
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.log
Text
to stdout
--- stderr
to stderr
ls: cannot access '/nonexistent': No such file or directory
--- trace.log
+ echo 'to stdout'
+ echo 'to stderr'
+ ls /nonexistent

When 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.

Share

More snippets

Debugging

Stop on the first error and show where

Report where a script failed with trap '...' ERR and set -E. LINENO gives the line, BASH_COMMAND the command and $? the status, even inside functions.

1 min read
Debugging

Print each line as it is read

Print every script line as the shell reads it, before expansion, with set -v. Pair it with set -x to see the source line and the expanded command.

1 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.