59

I am trying to read the output of a command in bash using a while loop.

while read -r line
do
    echo "$line"
done <<< $(find . -type f)

The output I got

ranveer@ranveer:~/tmp$ bash test.sh
./test.py ./test1.py ./out1 ./test.sh ./out ./out2 ./hello
ranveer@ranveer:~/tmp$ 

After this I tried

$(find . -type f) | 
while read -r line
do
    echo "$line"
done 

but it generated an error test.sh: line 5: ./test.py: Permission denied.

So, how do I read it line by line because I think currently it is slurping the entire line at once.

Required output:

./test.py
./test1.py
./out1
./test.sh
./out
./out2
./hello
3
70

There's a mistake, you need < <(command) not <<<$(command)

< <( ) is a Process Substitution, $() is a command substitution and <<< is a here-string.

0
14

Note that there's nothing stopping file names from containing newline characters. The canonical way to run a command for each file found by find is.

find . -type f -exec cmd {} \;

And if you want things done in bash:

find . -type f -exec bash -c '
  for file do
    something with "$file"
  done' bash {} +

Also, the canonical way to call the "read" command in scripts (if you don't want it to do extra processing on the input) is:

IFS= read -r var

-r is to stop read from treating backslash characters specially (as an escape character for separators and newline), And IFS= to set the list of separators to the empty string for read (otherwise if any whitespace character was in that list, they would be stripped from the beginning and end of the input).

Using loops in shells is usually a bad idea (not how things are done in shells where you make several tools work collectively and concurrently to a task rather than running one or more tools hundreds of times in sequence).

0
7

There's no need for command substitution if you want to use pipe:

find . -type f |
while read -r line
do
    echo "$line"
done

or in one line

find . -type f | while read -r line; do echo "$line"; done

Although as already noted, in case of find you'd be better off with its -exec option.

2
  • 1
    THIS is the answer I needed. After RTFM fails, S.E. comes to the rescue. Ha! TIL you can pipe into while read – Marian Minar Oct 3 '20 at 16:26
  • 1
    As a slightly more robust variant (for example, I ran into this "gotcha" once, with a filename that contained a newline (\n) in the name -- it can happen!), modify slightly as follows: find . -type f -print0 | while read -d '' line ... – michael Nov 10 '20 at 6:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.