2

Is it possible to both search recursively and with a given file pattern?

I am trying to do the equivalent of

find ./ -name "*.[c|h]" -exec grep -Hn PATTERN {} \;

Obviously you can use grep's -r flag, but when I specify a filename pattern such as:

grep -Hn -r PATTERN *.c

It only looks for *.c files in the current directory, not recursively.

I found this, but it does not talk about specifying filenames: Recursive grep vs find / -type f -exec grep {} \; Which is more efficient/faster?

2 Answers2

4

At least with recent versions of GNU grep, you can use glob patterns in a --include argument

grep -Hrn --include="*.[ch]" PATTERN .

[In GNU grep > 2.11 you may omit the explicit starting directory . when using -r]

steeldriver
  • 81,074
  • OSX grep also has that switch though patterns are matched to the full path as opposed to base name in GNU – don_crissti Jan 12 '17 at 17:54
  • I am using FreeBSD, this command just waits for STDIN, even though there is an --include flag. – Farhan Yusufzai Jan 12 '17 at 18:21
  • @FarhanYusufzai that may be due to differences in how grep selects directories for the -r case: even in GNU grep, older versions require an explicit starting directory argument e.g. grep -Hrn --include="*.[ch]" PATTERN . – steeldriver Jan 12 '17 at 18:27
2

The *.c is expanded by the shell before grep is even run. With a suitably fancy shell (e.g. zsh, or bash with globstar set), one can pre-expand recursively via something like

grep bla **/*.[ch]

But that is a shell solution. Other solutions would be to look at the file detection support in such tools as the silver searcher, codesearch, ripgrep.

Kusalananda
  • 333,661
thrig
  • 34,938