简体   繁体   中英

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

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 )

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM