Fiddlestiques
Fiddlestiques

Reputation: 83

Why does bash while loop try to process non-existent results of find?

I have a bash script using a while loop to get the basename for every file returned from a find command. I have simplified it to one line here:

$ while read myFile; do echo $(basename $myFile) ; done <<< $(find ./*test*  -maxdepth 1 -type f -exec ls {} + 2>/dev/null)
testRelease.sh

In the case of there being no results to the find command, I expected the condition of the while statement to be unfulfilled and the "do" section to be ignored. This is not the case:

$ while read myFile; do echo $(basename $myFile) ; done <<< $(find ./*noMatch*  -maxdepth 1 -type f -exec ls {} + 2>/dev/null)
basename: missing operand
Try `basename --help' for more information.

It looks as if the while statement adds a blank line which the condition is trying to process:

$ while read myFile; do echo $myFile ; done <<< $(find ./*noMatch*  -maxdepth 1 -type f -exec ls {} + 2>/dev/null)

$

This blank line does not appear when running the find command standalone. What is adding this blank line, and why does the while statement process it when no results are found?

Upvotes: 0

Views: 106

Answers (3)

user1934428
user1934428

Reputation: 22247

Even when there is no output, you feed at least one empty string into the loop. You can try it with a command which is guaranteed to produce no output. I use the null-command : for this experiment:

while read; do echo read=$REPLY; done  <<<$(:)

produces a single output line, saying just

read=

Upvotes: 1

Socowi
Socowi

Reputation: 27235

What is adding this blank line

The here string <<< is adding a trailing blank line. If you don't want it, you can use process substitution instead:

while read var; do ...; done < <(someCommand)

However, in your case you don't need a loop at all. find -exec can do the job for you much faster and safer:

find ./*test* -maxdepth 1 -type f -exec basename {} \; 2>/dev/null

Upvotes: 3

tshiono
tshiono

Reputation: 22022

Please let me simplify your command as:

while read line; do
    echo "line read"
done <<< $(find . 1>/dev/null)

The find command outputs nothing then the code above is equivalent to:

while read line; do
    echo "line read"
done <<< ""

It still prints "line read". The manpage of bash says:

A variant of here documents, the format is:

[n]<<<word

[lines snipped]
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).

Then the while loop reads an empty line to execute echo.
If you modify the code as:

while read line; do
    echo "line read"
done < <(find . 1>/dev/null)

it will output nothing.

Upvotes: 1

Related Questions