There is a lot going on in that loop. However, Bash is exceptionally well documented, and the manuals have a lot of really useful information. Here are snippets pulled directly from the manual that provide the answers you are looking for.
Everything in this section is taken from this page:
https://www.gnu.org/software/bash/manual/bash.html
3.2.4.1 Looping Constructs
while
The syntax of the while command is:
while test-commands; do consequent-commands; done
Execute consequent-commands as long as test-commands has an exit status of zero. The return status is the exit status of the last command executed in consequent-commands, or zero if none was executed.
5.1 Bourne Shell Variables
IFS
A list of characters that separate fields; used when the shell splits words as part of expansion.
4.2 Bash Builtin Commands
read
One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option, split into words as described above in Word Splitting, and the first word is assigned to the first name, the second word to the second name, and so on.
The characters in the value of the IFS variable are used to split the line into words using the same rules the shell uses for expansion (described above in Word Splitting).
-d delim
The first character of delim is used to terminate the input line, rather than newline. If delim is the empty string, read will terminate a line when it reads a NUL character.
-r
If this option is given, backslash does not act as an escape character. The backslash is considered to be part of the line. In particular, a backslash-newline pair may not then be used as a line continuation.
3.5.7 Word Splitting
If IFS is unset, or its value is exactly <space><tab><newline>, the default, then sequences of <space>, <tab>, and <newline> at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words.
3.6.1 Redirecting Input
Redirection of input causes the file whose name results from the expansion of word to be opened for reading on file descriptor n, or the standard input (file descriptor 0) if n is not specified.
The general format for redirecting input is:
[n]<word
3.5.6 Process Substitution
Process substitution allows a process’s input or output to be referred to using a filename. It takes the form of
<(list)
So with that relevant information, it is possible to piece together what this loop is doing:
while IFS= read -r -d $'\n'; do
num_proj+=("$REPLY")
done < <(find -iname "makefile*" -exec dirname {} \; | sort)
First, we should start with this command, since it provides the input to your read loop:
find -iname "makefile*" -exec dirname {} \; | sort
find is a program, and not a built-in, so the documentation for it is separate from the Bash documents. Feel free to look it up if you're interested, but in summary, this find command prints out all directories containing a file starting with the string "Makefile" (without case-sensitivity), one directory per line.
Now that we know the input is a list of directories, that brings us to the loop itself:
while IFS= read -r -d $'\n'; do
num_proj+=("$REPLY")
done
This construction will cause the inner loop to run one time for every line passed into it. Since we know that every line is one directory, the line num_proj+=("$REPLY") will run once for every directory.
All this combines to create a loop that appears to count the number of directories with a Makefile in it, to give an approximate count of the number of projects in sub-directories from where the program is run.
Now that it's clear what the program is doing as written, I think this can be rewritten to be both simpler and clearer. I would probably write this as follows:
IFS=$'\n' # We want to break up the input by only newlines, not whitespace.
for dir in $proj_list; do
num_proj+=("$REPLY")
done
unset IFS # always clean up IFS when you're done with it.
Much easier to follow, no?
find -iname "makefile*" -exec dirname {} \; | sort. Now put that back, but change the inside of the loop to justecho "|$REPLY|". Goto thebashdocumentation to see what the options-r -d $'\n'do for thereadcommand. You'll need to get used to this sort of research with any programming tool you use. Good luck.