skip to Main Content

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?

2

Answers


  1. 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
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search