53

I use recursive grep a lot to find source files with specific content.

grep -Rni "myfunc" .

On large codebases, this can get slow, so I use --incldue to restrict/whitelist extensions.

grep -Rni --include=*.java "myfunc" .

However, it would be more efficient to exclude (prune) whole subdirectories, I'm thinking:

grep -Rni --exclude=/.svn/ "myfunc" .

But the --exclude only supports file patterns like *.java above. How can I exclude directories?

gabor
  • 261
  • 2
  • 4
  • 8

6 Answers6

70
grep -r --exclude-dir=dev --exclude-dir=sys --exclude-dir=proc PATTERN data

Source: https://stackoverflow.com/questions/2799246/grep-excluding-a-specific-folder-using

Henrik
  • 1
  • 2
  • 2
  • 18
    Note that this recursively excludes. `./dev` will be excluded ALONG WITH `./foo/bar/dev`. Use `--exclude-dir=./dev` to only apply to the first case. – Cory Walker May 13 '13 at 14:08
  • 4
    You can also shorten this a bit by globbing: ```bash grep -r --exclude-dir={dev,sys,proc} PATTERN data ``` The only problem with globbing is that I cannot get it to work in my bash. In that case I have to keep them separate. – b01 Aug 13 '14 at 16:21
  • 3
    Also noted that {} only works if you put more than 1 entries, that means --exclude-dir={home,.svn} is works but --exclude-dir={.svn} will not works. It waste my time to figure out why {} doesn't work because i test with 1 entry in the first place. – 林果皞 Apr 28 '15 at 07:21
  • If you use `{}` with a single entry you probably need a unary comma to make it an array (not sure how Bash handles that). Instead of doing that I ended up making an alias in my .bash_aliases that loops over a list of folders I typically always want to exclude, eg .git, .svn, .hg, .cache, and then I add them via a loop with `--exclude-dir $dir` and then expand that array into the grep alias. – dragon788 Jul 02 '17 at 06:03
10

You might look into ack.

I've just started using it but it seems well-suited for this.

Alex Feinman
  • 275
  • 2
  • 12
  • ack looks pretty good. nice that it intuitively excludes unwanted files. the --nogroup option gives a similar output to grep -Rni – gabor Feb 12 '10 at 19:48
  • 2
    Ack is a bit slow. You can try The Silver Searcher (Ag) or ripgrep (rg). – user31389 Oct 19 '16 at 14:31
6

you can use find instead:

find . -not -path "*/.svn*" -not -type d -exec grep -ni "myfunc" {} \; -print

OK, so that's a little backwards, you get the grep results first and then the path. Maybe someoe else has a better answer?

Josh
  • 9,487
  • 11
  • 49
  • 70
  • 3
    ok, i like that a lot. of course find is a lot more flexible. the only difference between the output is that "grep -Rni" will print the file name for each match, whereas "find -exec grep" will print the filename on one line and then one line for each match (with line number and line content). using "grep -Hni" forces the filename to be displayed on each line – gabor Nov 06 '09 at 13:59
  • Thank you for providing the only answer that worked for systems which are this crusty, without grep --exclude-dir, but still gotta be worked on – Dmitri DB Sep 19 '16 at 10:21
2

Here's a full example from a script in one of my projects that might help, I call this file "all_source" (marked as executable) and put it in my project's root dir then call it like grep myfunc $(./all_source) the sort at the end of the script is totally optional.

#!/bin/bash

find . \
    -type d \( \
            -wholename './lib' -o \
            -wholename './vc6' -o \
            -name 'gen' -o \
            -name '.svn' \
            \) -prune -o \
    -type f \( \
            -name '*.h' -o \
            -name '*.cpp' -o \
            -name '*.c' -o \
            -name '*.lua' -o \
            -name '*.*awk' \) -print \
    | sort

This script returns all the file names in the project that match *.h, *.cpp, *.c, *.lua, *.*awk, but doesn't search in all folders named .svn and gen folders as well as skipping the folders for ./lib and ./vc6 (but only the ones right off the project root). So when you do grep myfunc $(./all_source) it only greps in those files. You'll need to call this from the root dir of the project as well.

aDev
  • 111
  • 2
0

You can try doing this:

grep -R  "myfunc" . | grep -v path_to_exclude/

Eg: If you don't want to search the content in log files just do the following:

grep -R "myfunc" . | grep -v log/
jherran
  • 1,879
  • 3
  • 20
  • 28
Akshatha
  • 101
  • 1
0

There is also the -prune option to find:

 find . -path "*/.svn*" -prune -o -not -type d -exec grep -ni "myfunc" {} \; -print
misiu_mp
  • 156
  • 3