Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to count all files in a directory that match a pattern, recursively, using ls:

ls -R | grep *.{cpp,h} | wc

However, I get:

zsh: no matches found: *.cpp

ls -R does return results, though:

$ ls -R CMakeLists.txt cmake src

./cmake: Modules SUBS.cmake

./cmake/Modules: FindGecode.cmake

./src: A1_examples.h Sub1Main.cpp Sudoku.cpp Sudoku.h nQueens.cpp

Why doesn't grep find the *.cpp files that ls -R returns?

Edit: I'm also pretty sure that ls -R | grep *.{cpp,h} | wc is not the best way to do this, because of the way that ls returns multiple results on single lines, but I'm not certain.

share|improve this question
what kind of syntax is {cpp,h} ? – barlop Apr 9 '12 at 12:01
As to the multiline: compare ls to ls | cat sometime. ls is smart enough to do multicolumn only when reporting directly (or when told to do so explicitly); it assumes -C for terminals and -1 for pipes. – geekosaur Apr 9 '12 at 12:07
@geekosaur I wasn't aware of that! Thanks. – simont Apr 9 '12 at 12:09
up vote 4 down vote accepted

You're making two different mistakes that play together. First, you need to quote the pattern sent to grep, otherwise the shell will expand it first. (That's where the error message comes from.) Second, grep does not accept shell globs, it wants a regex.

zsh being what it is, you may want to say

$ ls **/*.{cpp,h} | wc -l

instead, using a zsh-style recursive glob. If you want to use the other one, it's

$ ls -R | egrep '\.(cpp|h)$' | wc -l
share|improve this answer
Thanks. I've just been trying to get it working with plain grep rather than egrep (because I didn't know what the differences were). For my future reference: egrep is grep -E (enabled use of extended regular expressions; the brackets in the answer only work if the regular expression is an extended one). – simont Apr 9 '12 at 12:31
egrep is the original; grep -E is a GNUism. Also a GNUism is that you can use escaping instead: grep '\.\(cpp\|h\)'. Neither is portable. – geekosaur Apr 9 '12 at 12:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .