Try:
while IFS='' read -r line || [ "$line" ]
Yes, it is reading from standard input (stdin), the <test
redirection goes to stdin.
What might be happening is that read is designed to work with text files. Correct text files must end on a newline.
To make a file end on a newline turns out to be very fast:
[ -n "$(tail -c1 file)" ] && printf '\n' >>file
But if you can not edit the file to add a newline (if missing), the solution is to test (additionally) if something was read:
while read line || [ "$line" ]
That will make the loop execute if read failed (got to the end of the file without reading a newline (by default)) but something was read in (in "$line"
).
That will work correctly for files that do end on a newline or not.
No, a IFS='' read
will not (directly) affect the reading of the last line, in fact, the IFS=''
(compared to a default IFS[a] of space, tab, newline) will only affect the split into several variables (beside affecting the removal of leading and/or trailing white-space (if IFS contains only white space[b])). As there is only one variable ("$line"
) there is no splitting to be performed.
The -d
option to read (in bash since 2.04) will not help either. There is no specific "end of file" character to match (the last byte could be any).
The only options left are either:
- to repair the file to make it a correct text file
- test if anything was read into the variable
line
.
The correct script, then, will be:
#!/bin/bash
while IFS='' read -r line || [ "$line" ]
do
printf '%s\n' "$line"
done <test
IFS='' used to avoid problems with un-common values of IFS.
[a][b]Of course, If IFS may have any value, many other characters may get removed. Try (for values that end on 'x')
printf "test\ntesx\ntest" | while IFS="x" read -r line || [ "$line" ]; do echo "$line"; done
No, zsh does something different.
test
line terminated? What's the output ofod -vtc < /tmp/test
? Note that lines have to end in a newline character, otherwise they're just garbage after the last line. – Stéphane Chazelas Nov 04 '16 at 13:02od
output should appear as0000000 t e s t \n t e s t \n
– steve Nov 04 '16 at 14:49