8

In bash, this works:

echo -n $'a\nb\nc\n' | while read x; do echo = $x =; done

The while loops through three times

= a =
= b =
= c =

But imagine a text file that doesn't have the conventional trailing newline. I think that read should still work for all three lines, but it doesn't. I just get:

echo -n $'a\nb\nc' | while read x; do echo = $x =; done

= a =
= b =

The help read in bash doesn't really clarify.

Note: I don't need this resolved, and I can see some ways to fix it myself. I am curious, and I am tempted to file a bug report - I generally try myself to respect files that mightn't have the trailing new line. I came across this when using the -d option to read. read -d " " will split on spaces instead of newlines, but it will miss out on the last entry unless it has a trailing space.

(Ubuntu. GNU bash, version 4.1.5(1)-release)

3
  • for what it's worth, your 2nd script works as the first with ksh. Good luck. Commented Dec 22, 2011 at 22:06
  • I just checked: ksh behaves the same way as bash in this case, @shellter. Commented Jan 12, 2021 at 0:22
  • 1
    @codeforester : I'm sure I tested this before posting, but no longer have access to the UWIN ksh93. Also it is possible that the version I was using is different that the version you are using, although I'm almost sure I saw this very issue come up in the UWIN/ksh email groups (~<10 yrs ago ;-) ). I like your alternate below. Cheers. Commented Jan 12, 2021 at 0:52

2 Answers 2

11

If you want the above loop to process the incomplete line, do this:

echo -n $'a\nb\nc' | while read x || [[ $x ]]; do echo = $x =; done

which gives:

= a =
= b =
= c =

When read encounters the incomplete line, it does read that into the variable (x in this case) but returns a non-zero exit code which would end the loop, and || [[ $x ]] takes care of running the loop for the incomplete line as well. When read is called the next time, there is nothing to read and it exits with 1, setting x to an empty string as well, which ensures that we end the loop.


Related

Sign up to request clarification or add additional context in comments.

Comments

1
$ man bash
   read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
          One line is read from the standard input, ...

I think the key is: How to define "One line".
Does text without a '\n' at the end makes One line?
I guess read don't think so.

2 Comments

My text editor thinks it's a line, and I think every text editor will. So if the text editor can deal sensibly with files which don't have a newline as their very last character, then I think read should too :-)
read is correctly handling it - it reads every valid line. It doesn't read incomplete lines as it has no idea whether they're "lines", an interrupted stream, a broken pipe, etc.... Spec: a line; Spec: an incomplete line; read doesn't have the luxury of being able to assume that everything it operates on is a complete file intended for humans. Standards aren't based on what (often buggy) text-editors think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.