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 < file
And not
while read var file; do ...; done < file
Basically, 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"; done
v1:foo, rest:bar baz zab
$ echo "foo bar baz zab" | while read v1 v2 rest; do echo "v1:$v1, v2:$v2, rest:$rest"; done
v1: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"; done
v1:foo, v2:bar, v3:baz, rest:zab
As 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 >temp
while read lig
do
echo $lig "nombre de ligne" `wc -l < $lig`
done < temp
rm temp
Note 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 loop
while 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 loop
while IFS= read -r -d '' lig
do
echo "$lig nombre de ligne: $(wc -l < "$lig")"
done
$IFS
into as many variables as there are fields separated by$IFS
.$IFS
whitespace and$IFS
otherwise behave differently in that$IFS
whitespace separates fields by contiguous sequence and can never generate null-length fields, but any other$IFS
chars account for a field separator per - and contiguous sequences result in null-length vars assignments. Also backslashes are interpreted as escapes by default - even to escape newlines into nothing, for example - and leading/trailing$IFS
chars are stripped entirely. – mikeserv Nov 10 '15 at 11:36find
you use doesn't support the non-standard options you specify. in those cases it will get about as far as ERROR. truly robust without the needless pipe construct isfind . ... -exec sh -c 'for f do printf %s:\ "$f nombre de ligne"; wc -l <"$f"; done' ligecho {} +
where the null delimiting is handled in the standard way by argument in the kernel. – mikeserv Nov 10 '15 at 11:46-print0
which is supported by the vast majority offind
implementations including GNU, BSD and even busybox. The only one I could find that doesn't seem to support it is AIX and I very much doubt the OP is using AIX. – terdon Nov 10 '15 at 12:02read -d ""
which is not a standard option. its the other end of the non-standard-print0
. so you compound them, and wind up with a slower and less reliable method than the standard one. and anyway,-print0
andread -d
dont have anything to do withwhile
either. and your answer doesnt addresswhile
.while
works by repeating the same compound command until it returns other than 0.read
returns other than 0 when it reads an EOF. thats how it works. thats why i piped up in the first place, really. – mikeserv Nov 10 '15 at 12:10