From: Martin Wheatley
Subject: Philosophical bash(1) bug
Date: Tue, 02 Dec 2025 16:36:19 -0000
>I have recently identified a failure mode in bash(1) scripts that has
>plagued us with random process failures for over 20 years!
>The read(1) built-in command has the -t option to specify a timeout on
>the read and it appears that the TMOUT variable is also honoured as an
>alternative if it is defined (and this is where I think there is an issue).
>From the bash(1) manual entry...
> The time-out is applied if read(1) is reading from a terminal,
> pipe or other special file.
>Since TMOUT can be inherited from a much 'higher' process a script has
>no knowledge about whether it has been set or not nor whether the value
>is appropriate for the script.
For reference, here is the entry for "TMOUT" in "man bash":
--- Cut Here ---
TMOUT If set to a value greater than zero, TMOUT is treated as the default
timeout for the read builtin. The select command terminates if input
does not arrive after TMOUT seconds when input is coming from a terminal.
In an interactive shell, the value is interpreted as the number of
seconds
to wait for a line of input after issuing the primary prompt. Bash
terminates after waiting for that number of seconds if a complete line of
input does not arrive.
--- Cut Here ---
I think that is pretty clear - that TMOUT affects the "read" builtin,
wherever it may be called. I.e., that the phrase "the read builtin"
extends beyond just the read builtin (if you see what I mean). It
affects (inter alia) "select" and the interactive shell prompt.
I think the primary intended use of TMOUT is the last case listed
above - i.e., to timeout an interactive shell if the user is idle for
too long. But the point is that in order for that to work properly,
you need to have it timeout in the other places where the shell might
be sitting waiting for the user to type something - e.g., in a
"select" statement or in a "read" statement.
So, having said all that, I think it is working as designed and
that's good. But here's the thing: the problem you are describing can
only happen if TMOUT is both set *and* exported (*). I don't think
TMOUT should normally be exported. Even though it is in all caps -
and all caps usually indicates an exported variable - this one should
not generally be exported - it is intended to be local to the specific
shell (usually an interactive shell) in which it is set.
Note that there are a few other all caps variables which are usually
not exported - e.g., HOSTNAME. You can test to see if a variable is
exported via something like: echo ${HOSTNAME@a}
If that shows an x, it is exported.
(*) So that its value cascades down from the interactive shell into
the scripts you run.
=================================================================================
Please do not send me replies to my posts on the list.
I always read the replies via the web archive, so CC'ing to me is unnecessary.
When responding to my posts, please try to refrain from giving bureaucratic
answers.
If you have nothing useful to say, then just click Next and go on.