Reputation: 328
A very simple way to demonstrate this is to run
mkfifo /tmp/a
read -t 1 a < /tmp/a
the read never return.
Bash Manual says: This option is only effective if read is reading input from a terminal, pipe, or other special file; it has no effect when reading from regular files
but /tmp/a is a pipe, output of ls is
ls -l /tmp/a
prw-r--r-- 1 root root 0 Feb 4 22:18 /tmp/a
the bash version is:
GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2013 Free Software Foundation, Inc.
the OS is:
Ubuntu 16.04.1 LTS
Upvotes: 5
Views: 1322
Reputation: 6134
See my detailed answer on unix.stackexchange.com.
TL;DR: your -t
flag does not seem to work because read
is even not executed since this is your shell that is blocked, not your command.
Before executing your read
command, bash
tries to open /tmp/a
and this is a blocking operation. Opening a named pipe for reading blocks until someone else opens it for writing.
You can check this with an erroneous command:
mkfifo my_fifo
a_command_that_does_not_exist < my_fifo
(your shell is blocked until someone opens my_fifo
for writing, and only then will it tell you command not found
)
Solution: read -t 1 a <> /tmp/a
(more on unix.stackexchange.com)
Upvotes: 3
Reputation: 19545
I just confirm that timeout does not work on a pipe stream because of a race condition. The sub-shell is executing the read
statement before the input is made available.
Running:
echo 'hello' | {
if read -t0
then echo 'Input is available.'
else echo 'No input available on the FD.'
fi
}
Outputs:
No input available on the FD.
Introducing a dummy :
NOP command ( or wait 1
) before the read
, can change the deal:
echo 'hello' | {
:
if read -t0
then echo 'Input is available.'
else echo 'No input available on the FD.'
fi
}
Then suddenly:
Input is available.
Upvotes: 0
Reputation: 121347
When you read from the pipe, there needs to be someone writing to the pipe as well. "pipe" is just a communication mechanism. It doesn't "generate" any input by itself; it'll just pass the its input to its output end. It appears that you are just reading but there's no one writing to /tmp/a
.
When read
waits for input do echo hello > /tmp/a
from another terminal and you'll see that read
returns and a
has the value "hello".
Read about pipes in detail here: http://man7.org/linux/man-pages/man7/pipe.7.html
Upvotes: 1