bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: BASH_XTRACEFD=1 read variable stdout flushing?


From: Emanuele Torre
Subject: Re: BASH_XTRACEFD=1 read variable stdout flushing?
Date: Mon, 16 Jan 2023 20:42:02 +0100
User-agent: Mutt/2.2.9 (2022-11-12)

On Mon, Jan 16, 2023 at 11:36:18AM -0600, dave.drambus@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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]