My script (should) acts differently, depending on the presence of the data in the input stream. So I can invoke it like this:
$ my-script.sh
or:
$ my-script.sh <<-MARK
Data comes...
...data goes.
MARK
or:
$ some-command | my-script.sh
where two last cases should read the data, while first case should notice the data is missing and act accordingly.
The crucial part (excerpt) of the script is:
#!/bin/bash
local myData;
read -d '' -t 0 myData;
[ -z "${myData}" ] && {
# Notice the lack of the data.
} || {
# Process the data.
}
I use read
to read input data, then option -d ''
to read multiple lines, as this is expected, and the -t 0
to set timeout to zero. Why the timeout? According to help read
(typing left unchanged; bold is mine):
-t timeout
time out and return failure if a complete line of input is
not read withintTIMEOUT
seconds. The value of theTMOUT
variable is the default timeout.TIMEOUT
may be a
fractional number. IfTIMEOUT
is 0, read returns success only
if input is available on the specified file descriptor. The
exit status is greater than 128 if the timeout is exceeded
So I in case 2 and 3 it should read the data immediately, as I understand it. Unfortunately it doesn't. As -t
can take fractional values (according to above man page), changing read line to:
read -d '' -t 0.01 myData;
actually reads the data when data is present and skips it (after 10ms timeout) if it is not. But it should also work when TIMEOUT
is set to real 0
.
Why it actually doesn't? How can this be fixed? And is there, perhaps, alternative solution to the problem of "act differently depending on the presence of the data"?
UPDATE
Thanks to @Isaac I found a misleading discrepancy between quoted on-line version and my local one (normally I do not have locale set to en_US, so help read
gave me translation which I couldn't paste here, and looking up for on-line translation was faster than setting new env—but that caused the whole problem).
So for 4.4.12 version of Bash it says:
If TIMEOUT is 0, read returns
immediately, without trying to read any data, returning
success only if input is available on the specified
file descriptor.
This gives a little bit different impression than "If TIMEOUT is 0, read returns success only if input is available on the specified file descriptor"—for me it implied actually an attempt to read the data.
So finally I tested this and it worked perfectly:
read -t 0 && read -d '' myData;
The meaning: see if there's anything to read and if it succeed, just read it.
So as to base question, the correct answer was provided by Isaac. And as to alternative solution I prefer the above "read && read" method.
Best Answer
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 calledread
. That is not the manual for the builtin bashread
.To read bash man page use
man bash
and search forread [-ers]
or simply use:Which contains this (on version 4.4):
So, no, no data will be read with
-t 0
.Because that is the documented way it works.
Only if that is accepted as a bug (I doubt it will) and the bash source code is changed.
Yes, actually, there is a solution. The next sentence of
help read
after what I quoted above reads:Which means that even if it doesn't read any data, it could be used to trigger an actual read of available data:
That will have no delay.