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?

  • "I was expecting the above command to hang as the read continuously waits for input" Why were you expecting that? – mosvy Apr 20 at 11:00
  • @mosvy: Because read command is supposed to continuously read input until it encounters a newline. – user15740 Apr 20 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 ;-) – mosvy Apr 20 at 11:21
  • @mosvy: I agree. My question really is though, how did the eof get there? – user15740 Apr 20 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. – Paul_Pedant Apr 20 at 12:07
4

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.

| improve this answer | |
  • 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 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 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 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.