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.
sleep 0.01
before theread -t0
?-t 0.01
is shorter... Still it's a hack. ;-)read
timeouts work with non-ttys, but a workaround might beif [ -t 0 ]; then echo not file or pipe, so no data; else read -d '' myData; ... ; fi