0

When I give this command:

$echo -n "Hello"

Hello$

I get the above output. This means echo -n prints the string without the terminating newline.

Now, I pipe the output to read, where the read command is supposed to keep reading until it encounters a newline.

$echo -n "Hello" | read

$

At the above command, the command prompt is returned. However, I was expecting the above command to hang as the read continuously waits for input because it didn't encounter a newline. Why doesn't this happen?

5
  • "I was expecting the above command to hang as the read continuously waits for input" Why were you expecting that?
    – user313992
    Apr 20, 2020 at 11:00
  • @mosvy: Because read command is supposed to continuously read input until it encounters a newline.
    – user15740
    Apr 20, 2020 at 11:18
  • Why it's supposed to do that? Both the bash's and the standard documentation are telling that it should return a non-zero status if hitting the EOF before a newline. I could just as well claim that read should be print an error message if instead of echo Hello, I'm using echo Help ;-)
    – user313992
    Apr 20, 2020 at 11:21
  • @mosvy: I agree. My question really is though, how did the eof get there?
    – user15740
    Apr 20, 2020 at 11:44
  • EOF is not something that is 'there' in the pipe. It is an attribute of the pipe itself, specifically 'this pipe has now sent you everything it ever will'. Read is too smart to keep waiting for something that can never happen. Apr 20, 2020 at 12:07

1 Answer 1

5

If you investigate the exit-status of that pipeline, you will notice that read returns 1:

$ echo -n "Hello" | read
$ echo $?
1

It returns 1 because it encountered an end-of-file condition and therefore failed to read more data. The input stream from echo was closed because echo had finished its task and terminated, closing that side of the pipe.

The data read before the input stream from echo was closed would still be available in the REPLY variable:

$ echo -n "Hello" | { read; echo "$REPLY"; }
Hello

In short, read does not wait for further input because it noticed that the input stream was closed.

Also (tangentially) related: What is meant by "keeping the pipe open"?


You may possibly come across loops like these:

while read variable || [ -n "$variable" ]; do
    # something with "$variable"
done

This allows for reading input that may not be properly terminated by a final newline character. Without the -n test, and without a final newline character in the data, the last (non-terminated) line would otherwise be skipped.

The read utility used in this loop acts like a test. If the input stream that the loop is connected to closes (the read reads past the end of the file), read would return a non-zero exit-status, and the loop would terminate. With the -n test, it does one extra iteration, but that extra iteration will just confirm that, yes, there is no more data to read and now the value $variable is also empty.

3
  • Hi, Thanks for your answer. The question is though, how did it encounter the eof if it wasn't explicitly put there? How did the input stream get closed? Who closed it?
    – user15740
    Apr 20, 2020 at 11:15
  • 1
    @user15740 The input stream was close as soon as echo was done. I will make this clearer in the answer.
    – Kusalananda
    Apr 20, 2020 at 11:22
  • @user15740 Also, end-of-file is a condition of the input stream, not a thing that arrives over that stream.
    – Kusalananda
    May 8, 2020 at 19:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .