I'm learning about shell scripting and I have some difficulties understanding the development of the main command structures needed to write a script, especially with the while,do and done commands.I know that when redirecting the standard input of the while instruction from a file, it will stop once the whole file has been read (in this case, the file is read line by line and the current line is placed in a variable used by read):while read lig fichdo...done < fichdoes it mean that we have an entire curent line in fich?For instance: this script take a username and a string as arguments, it searches for files  gives owned by the username and whose name contains the string:#usage nblign nom-utilisateur chainefind . -user $1 | grep $2 >tempwhile read lig tempdoecho $lig nombre de ligne `wc -l < $lig`$done < temprm tempHere, my teacher ommited $ before lig in while is it a typo? Because in order to have the result of a command or a variable, one must use $ to retrieve it.
How to redirect the standard input of the `while` instruction on a file?
shell script
You have a few misconceptions. First of all, the format of the while read ... do you are trying to use is:while read var; do ...; done < fileAnd notwhile read var file; do ...; done < fileBasically, while read var; do ...; done < file will read each line of file and save it as var. Anything between read and do is taken as a variable. If you give more than one variable, then the line will be split on whitespace (well, on the value of the $IFS variable which is \t,\n and space, by default) and saved into the variables given. As explained in help read:Reads a single line from the standard input, or from file descriptor FD      if the -u option is supplied.  The line is split into fields as with word      splitting, and the first word is assigned to the first NAME, the second      word to the second NAME, and so on, with any leftover words assigned to      the last NAME.So, for example:$ echo foo bar baz zab | while read v1 rest; do echo v1:$v1, rest:$rest; donev1:foo, rest:bar baz zab$ echo foo bar baz zab | while read v1 v2 rest; do echo v1:$v1, v2:$v2, rest:$rest; donev1:foo, v2:bar, rest:baz zab$ echo foo bar baz zab | while read v1 v2 v3 rest; do echo v1:$v1, v2:$v2, v3:$v3, rest:$rest; donev1:foo, v2:bar, v3:baz, rest:zabAs you can see above, the input line is split into as many variables as you give. When there are fewer variable names than words in the input, the last variable gets the rest of the line. This is exactly the same when reading from a file. Then, variables are set using var=foo and are read using $var. So no, your teacher was right, you don't want the $ when the variable is being defined. Therefore while read var is correct and while read $var is wrong. So, a working version of your script, using the same logic, would be:find . -user $1 | grep $2 >tempwhile read lig do    echo $lig nombre de ligne `wc -l < $lig`done < temprm tempNote that I removed the temp from the read and the $ from the end of the echo line. I have no idea why you put that there. A better version of your script, with your variables correctly quoted, using find to find the relevant files instead of attempting to parse and  without needless temp files would be:find . -user $1 -name *$2* |## No need for a temp file, just pipe the output directly## to the while loopwhile read lig do    echo $lig nombre de ligne: $(wc -l < $lig)done Finally, a truly robust approach which, unlike the above, can deal with arbitrary file names, including those with whitespace or other strange characters: find . -user $1 -name *$2* -print0 |## No need for a temp file, just pipe the output directly## to the while loopwhile IFS= read -r -d '' lig do    echo $lig nombre de ligne: $(wc -l < $lig)done 