Why bash "read -t 0" does not see input?

Disclosure: not a rigorous answer, lots of handwaving

There are several things at play here. First, bash handles zero timeout internally totally differently from non-zero timeouts. (If you decide to look at the code, be prepared for spending some time on it - it is not as straightforward as one might expect; it goes rather deep.)

Second, there's an inherent race condition when working with pipes - the processes are created "from right to left", i.e. the last process on the command line is created first. However it is not guaranteed the shell will continue executing, spawning further process from the command line, before the ones already created get scheduled themselves - thus it may well happen that the read is executed before the input is ready. Depending on the particular system, if you play a bit with the timeout value, you may be able to reproduce the -t 0 behaviour with something like -t 0.00001.1)

On top of the above, consider that most systems these days are parallel (either multi-core or multi-processor) - you will get different results depending on how the kernel schedules all the processes in the pipeline (one thing that influences that will be the current system load, btw). This problem may be alleviated, by restricting the process group to a single particular CPU (e.g. with taskset), but the problem with scheduling of child processes mentioned above is not going to go away.


1) I actually managed to get to a point, where read only received part of the input (1 or 2 characters out of 3).


No, read -t 0 will not read any data.

You are reading the wrong manual. The man read will give the manual of a program in PATH called read. That is not the manual for the builtin bash read.

To read bash man page use man bash and search for read [-ers] or simply use:

help read

Which contains this (on version 4.4):

If timeout is 0, read returns immediately, without trying to read any data.

So, no, no data will be read with -t 0.


  1. Q1

    Why it actually doesn't?

Because that is the documented way it works.

  1. Q2

    How can this be fixed?

Only if that is accepted as a bug (I doubt it will) and the bash source code is changed.

  1. Q3

    And is there, perhaps, alternative solution to the problem of "act differently depending on the presence of the data"?

Yes, actually, there is a solution. The next sentence of help read after what I quoted above reads:

returning success only if input is available on the specified file descriptor.

Which means that even if it doesn't read any data, it could be used to trigger an actual read of available data:

read -t 0 && read -d '' myData

[ "$myData" ] && echo "got input" || echo "no input was available"

That will have no delay.

Tags:

Bash

Read