4

If I set -x in my bash session ( v4.1.2(2) - CentOS 6.10), I get :

$ ls /root
+ ls --color=auto /root
ls: cannot open directory /root: Permission denied

Great, it echo's the command I ran and prints out the terminal. This is expected. Now if I redirect both stdout and stderr to the another file.

$ ls /root  &> stuff.txt
+ ls --color=auto /root

It still prints the command to the terminal.

QUESTION

Where is set -x having bash print to if it isn't stderr or stdout?

irritable_phd_syndrome
  • 4,631
  • 3
  • 32
  • 60

2 Answers2

12

The set -x command prints tracing information to stderr.

When you run this command...

ls /root  &> stuff.txt

You're only redirecting stdout and stderr for the ls command. You're not changing either for your current shell, which is where you have run set -x.


As Mad Physicist points out, the technical answer is "it logs to BASH_XTRACEFD", which defaults to stderr. You can redirect trace logging for the current shell to another file by doing something like:

# open a new file descriptor for logging
exec 4> trace.log

# redirect trace logs to fd 4
BASH_XTRACEFD=4

# enable tracing
set -x
larsks
  • 277,717
  • 41
  • 399
  • 399
3

When you execute a command, you can redirect the standard output (known as /dev/stdout) of the command directly to the file. Also if the command generates error-output (generally send to /dev/stderr) you can also redirect it to a file as:

$ command > /path/to/output.txt 2> /path/to/error.txt

When you execute the command set -x, you ask it to generate a trace of the commands being executed. It does this by sending messages to /dev/stderr. In contrast to a normal command, you cannot easily redirect this in a similar way as with a normal command. This is because bash executes the script and at the same time generates the trace to /dev/stderr. So if you would like to catch the trace, you would have to redirect the error output of bash directly. This can be done by the command

 exec 2> /path/to/trace.txt

note: this will at the same time also contain all the error output of any command executed in the script.

Examples:

#!/usr/bin/env bash
set -x
command

This sends all output and error output to the terminal

#!/usr/bin/env bash
set -x
command 2> /path/to/command.err

This sends the output of command and the trace of bash to the terminal but catches the error output of command in a file

#!/usr/bin/env bash
set -x
exec 2> /path/to/trace.err
command 2> /path/to/command.err

This sends the output of command to the terminal, the error output of command to a file, and the trace of the script to /path/to/trace.err

#!/usr/bin/env bash
set -x
exec 2> /path/to/trace_and_command.err
command

This sends the output of command to the terminal, the trace and the error of command to a file.

Yushin
  • 1,684
  • 3
  • 20
  • 36
kvantour
  • 25,269
  • 4
  • 47
  • 72