ls *.c | wc -l
Of course, that's really the wrong way to write that anyway, since it does a lot more work than necessary, and it also breaks on some combinations of data.
You've told the shell to expand *.c. It does. Then it passes that to "ls", which takes each argument (and at this point, we already know how many C files there are, so the rest of this is wasted CPU) and looks each file up.
And ls says "yes, that's a file" and spits it to standard out on a line by itself.
Or sometimes it does. If there's a directory for that dot-c file instead of a file, you get the contents of the directory. BUG.
Or, if the filename contains a newline, it takes up more than one line. BUG.
But then wc gets fired up, counting all those newlines, and replies back with a integer on standard out. Yeah, finally, there's your number, sorta, subject to two classes of bugs and firing off two (or three, if you're trying to catch the output) processes needlessly.
How should this have been done instead?
$ set -- *.c; count=$#
Done. No forking, everything done in the One True Shell (/bin/sh). Far too easy. And not subject to whitespace problems, either spaces or newlines.
Admittedly kills the $* array, but by the time you get to this stage, you've generally processed that anyway.
Your code belongs in a textbook of "how not to code in the shell". The sad part is, you probably copied this from someone else, who probably copied it from someone else. So it becomes this crazy meme that is broken and inefficient, but everyone copies. That's where I come in... the "bad meme killer", similar to my complaints about "useless use of cat" and "bad use of kill -9" and "ref($proto)", and so on.
| [reply] [d/l] [select] |