yuanjianpeng
yuanjianpeng

Reputation: 328

bash `read -t` doesn't work on pipe

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

Answers (3)

xhienne
xhienne

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

L&#233;a Gris
L&#233;a Gris

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

P.P
P.P

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

Related Questions