shell script does not read last line from sysin

233 views Asked by At

I try to get some data from sysin and here is my problem: if data are directed from a file, then the last line is not read. Example of text file:

line1
line2
line3

My code:

#!/bin/bash
while read line
do
  echo "$line"
done

And output:

$ ./test.sh < data.txt
line1
line2

If I write down at the end of my file null string output correct. But I don`t like it. How to fix this?

3

There are 3 answers

1
gudok On BEST ANSWER

If you need desperately to read files without EOL in the end, then you may check whether returned string is empty or not instead of checking read exit status:

#!/bin/bash
while true; do
  line=''
  read line
  if [ -z "$line" ]; then
    break
  fi
  echo "$line"
done
3
Andreas Louv On

I bet you that data.txt is missing a trailing newline, try checking with

od -xa data.txt

Look at the end:

$ od -xa data.txt
0000000    696c    656e    0a31    696c    656e    0a32    696c    656e
          l   i   n   e   1  nl   l   i   n   e   2  nl   l   i   n   e
0000020    0033
          3
0000021

If you see the above you are missing the newline.

$ od -xa data-with-nl.txt
0000000    696c    656e    0a31    696c    656e    0a32    696c    656e
          l   i   n   e   1  nl   l   i   n   e   2  nl   l   i   n   e
0000020    0a33
          3  nl
0000022

Some shells will also show a % sign if trailing newline is missing, try:

$ cat data.txt
line1
line2
line3%
$
0
Charles Duffy On

The idiom for this is:

while read -r line || [[ $line ]]; do
  : process "$line"
done

Thus, we proceed in the loop while either:

  • We read a valid line of text (which requires a newline)
  • We had a partial read (which results in a nonzero exit status, but leaves the variable non-empty).