[[ -n "$line" ]]
tests if $line
(the variable just read by read
) is not empty. It's useful since read
returns a success if and only if it sees a newline character before the end-of-file. If the input contains a line fragment without a newline in the end, this test will catch that, and the loop will process that final incomplete line, too. Without the extra test, such an incomplete line would be read into $line
, but ignored by the loop.
I said "incomplete line", since the POSIX definitions of a text file and a line require a newline at the end of each line. Other tools than read
can also care, e.g. wc -l
counts the newline characters, and so ignores a final incomplete line. See e.g. What's the point in adding a new line to the end of a file? and Why should text files end with a newline? on SO.
The cmd1 || cmd2
construct is of course just like the equivalent in C. The second command runs if the first returns a falsy status, and the result is the exit status of the last command that executed.
Compare:
$ printf 'foo\nbar' | ( while read line; do
echo "in loop: $line"
done
echo "finally: $line"
)
# prints:
# in loop: foo
# finally: bar
and
$ printf 'foo\nbar' | ( while read line || [[ -n $line ]]; do
echo "in loop: $line"
done
echo "finally: $line"
)
# prints:
# in loop: foo
# in loop: bar
# finally: