Oops. > And there is no reason to not use it since any bash version that > supports BASH_XTRACEFD, also supports {var}<&fd syntax.
Of course, I meant to say that there is no reason to use BASH_XTRACEFD=1 over exec {BASH_XTRACEFD}<&1 . I forgot to change this paragraph after moving the suggestion of using exec {BASH_XTRACEFD}<&1 to the bottom. emanuele6 On 16/01/2023, Emanuele Torre <torreemanue...@gmail.com> wrote: > On Mon, Jan 16, 2023 at 11:36:18AM -0600, dave.dram...@gmail.com wrote: >> Description: >> >> I have `set -x` and `BASH_XTRACEFD=1` set in a simple script that I have >> in >> a cron job. I'd like to see the progress of the script when run >> manually, >> hence `set -x`, but I want the output to go to stdout rather than stderr >> so >> that cron emails me only when there is an actual failure. With this >> configuration, the `read` command is erroneously reading the "+" prompt >> output from `set -x` into the variable. It seems like stdout is not >> getting >> flushed propertly. > > BASH_XTRACEFD=something is generally not what people want, but it is a > very common bad pattern people use. > > And there is no reason to not use it since any bash version that > supports BASH_XTRACEFD, also supports {var}<&fd syntax. > > Problems with BASH_XTRACEFD=fd: > 1. Assignments to BASH_XTRACEFD are special, the old value of > BASH_XTRACEFD implictly gets closed when a new value is assigned to > it. > If you e.g. use > > #!/bin/bash -- > BASH_XTRACEFD=2 > set -x > cmd # xtrace behaves like normal, output to stderr (2) > exec 3> log > BASH_XTRACEFD=3 # this line sets XTRACEFD to 3, but also closes 2 > cmd # xtrace output written to ./log > BASH_XTRACEFD=2 # this sets XTRACEFD back to 2, it also > # implictily closes 3 > cmd # stderr (2) is closed, so there is no xtrace > # output even if set -x is on > > Not your problem, but a common pitfall nonetheless. > > 2. BASH_XTRACEFD tells xtrace what fd to write to. BASH_XTRACEFD=1 is > not interpreted as "write xtrace to the current stdout", but as > "write xtrace to stdout, whatever stdout is at the time of writing". > In the case of stdout, this will break stuff like $() or |, etc. as > you can observe with your problematic script. Unless you do not > actually want to capture stdout output, do not use BASH_XTRACEFD=1. > > Instead, just use exec {BASH_XTRACEFD}<&1 that assigns to > BASH_XTRACEFD a file descriptor that is a dup of 1. > > #!/bin/bash -- > exec {BASH_XTRACEFD}<&1 > set -x > ... > > This way 1) the dup gets closed instead of stdout when BASH_XTRACEFD is > reassigned/unset; 2) stuff like $() or | redirecting stdout doesn't > affect xtrace. > > Cheers. > emanuele6 >