Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where does `set -x` cause bash to print to?

Tags:

bash

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?

like image 609
irritable_phd_syndrome Avatar asked Dec 13 '22 09:12

irritable_phd_syndrome


2 Answers

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
like image 124
larsks Avatar answered Dec 15 '22 22:12

larsks


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.

like image 42
kvantour Avatar answered Dec 15 '22 22:12

kvantour