What’s happening?
I understand that you’re trying to solve a particular problem,
but one of the first rules of debugging is to simplify the scenario.
If we do
$ sleep 1 | read x
$ echo "$?"
1
$ read x <<< $(sleep 1)
$ echo "$?"
0
we see that a read
from an empty pipe fails,
but a read
from a null here string succeeds (reading a null value).
That is what you are seeing.
And it’s spelled out in bash(1):
Here Strings
A variant of here documents, the format is:
The word
undergoes tilde expansion, parameter and variable expansion,
command substitution, arithmetic expansion, and quote removal.
Pathname expansion and word splitting are not performed.
The result is supplied as a single string, with a newline appended,
to the command on its standard input
(or file descriptor n
if n
is specified).
(emphasis added)
Bash turns a null here string into a blank line, not an EOF.
How to fix it?
The obvious — modify the loop logic:
while read dir && [ "$dir" != "" ]
do
echo "HereDoc find: $dir"
done <<< "$(find /empty_directory -mindepth 1 -maxdepth 1 -type d)"
This terminates the loop if it reads a blank line.
Equally obvious — modify the logic in the loop:
while read dir
do
if [ "$dir" = "" ]; then continue; fi
echo "HereDoc find: $dir"
done <<< "$(find /empty_directory -mindepth 1 -maxdepth 1 -type d)"
This ignores blank lines (but doesn’t terminate the loop).
Perhaps better — modify the redirection:
while read dir
do
echo "HereDoc find: $dir"
done < <(find /empty_directory -mindepth 1 -maxdepth 1 -type d)
By using process substitution
(
<(command)
)
and simple redirection (
<
) instead of command substitution
(
$(command)
)
and a here string (
<<<
), you prevent Bash from adding the newline.
P.S. Note that you don’t need to have a semicolon (;
)
at the end of a line, as you have done with while read dir
.