I want to traverse all subdirectories, except the node_modules directory.
 
    
    - 3,482
- 3
- 38
- 50
 
    
    - 259,804
- 351
- 777
- 1,080
- 
                    3See http://superuser.com/q/66715/59933 – borrible Jul 03 '11 at 20:55
- 
                    78If you are grepping for code in a git repository and `node_modules` is in your `.gitignore`, `git grep "STUFF"` is the easiest way. `git grep` searches the tracked files in the working tree, ignoring everything from `.gitignore` – 0xcaff Dec 22 '16 at 21:51
- 
                    7An example for node: `grep -R --exclude-dir={node_modules,bower_components} "MyString" | cut -c1-"$COLUMNS"` -- further you could always alias this in the shell to 'nodegrep' or whatever and use a command argument as string input.. – B. Shea Mar 21 '18 at 21:59
14 Answers
Recent versions of GNU Grep (>= 2.5.2) provide:
--exclude-dir=dir
which excludes directories matching the pattern dir from recursive directory searches.
So you can do:
grep -R --exclude-dir=node_modules 'some pattern' /path/to/search
For a bit more information regarding syntax and usage see
- The GNU man page for File and Directory Selection
- A related StackOverflow answer Use grep --exclude/--include syntax to not grep through certain files
For older GNU Greps and POSIX Grep, use find as suggested in other answers.
Or just use ack (Edit: or The Silver Searcher) and be done with it!
 
    
    - 3,782
- 4
- 16
- 33
 
    
    - 136,902
- 23
- 188
- 247
- 
                    4@Manocho: If you think `ack` is great, try The Silver Searcher and see the speed increase! – johnsyweb Nov 13 '13 at 22:08
- 
                    47Syntax for the impatient: `--exclude-dir=dir` uses `grep`'s regular expression patterns, _not_ shell's file globbing. Patterns work on paths relative to your current directory. So use pattern `--exclude-dir=dir`, not `--exclude-dir="/root/dir/*"`. – tanius Feb 08 '14 at 17:39
- 
                    
- 
                    25If you wish to exclude multiple dirs from the search, is there a better option than to use : `$ grep -r --exclude-dir=dir1 --exclude-dir=dir2 "string" /path/to/search/dir` ? – Darshan Chaudhary Nov 25 '15 at 06:21
- 
                    @DarshanChaudhary: What do you mean by 'better'? That looks like a good approach to me. – johnsyweb Nov 25 '15 at 08:50
- 
                    2@Johnsyweb, I was hoping for something where I did not have to mention `--exclude-dir` multiple times. – Darshan Chaudhary Nov 25 '15 at 09:53
- 
                    
- 
                    @TylerLong: I use `grep` from homebrew-dupes: https://github.com/Homebrew/homebrew-dupes/blob/master/grep.rb – johnsyweb May 06 '16 at 02:24
- 
                    19I probably spent way too much time on this than any sane person, but I can't for the life of me figure out how to exclude a subdirectory from the search - `grep -r --exclude-dir=public keyword .` works, but `grep -r --exclude-dir='public/dist' keyword .` does not. I tried adding regex wildcards, escaping characters etc, but nothing seems to help. – dkobozev Jul 06 '16 at 23:47
- 
                    109Exclude multiple directories like so: `grep -r "Request" . --exclude-dir={node_modules,git,build}` – maverick97 Jul 12 '16 at 08:00
- 
                    Is there a way to add this to all grep commands I make so I don't need to manually type it every time? – Matthew Herbst May 30 '17 at 22:02
- 
                    2
- 
                    @MatthewHerbst you can make an alias as suggested or export it using GREP_OPTIONS (or a similar) variable I believe. I prefer the alias route in case I really do need to search in one of the excluded directories or with different options I can just bypass the alias. – dragon788 Jul 02 '17 at 05:44
- 
                    1@dragon788: `GREP_OPTIONS` is deprecated: https://git.savannah.gnu.org/cgit/grep.git/commit/?id=50d843674e5df9f5d0111f07bbff8ce07c19df6a – johnsyweb Jul 04 '17 at 06:41
- 
                    1@dkobozev to exclude specific subdirectories you must start with the dot, so using `grep -r --exclude-dir='./public/dist' keyword` should be what you're looking for – ErikAGriffin Mar 09 '19 at 19:43
- 
                    1Don't use the relative path, i.e. just `--exclude-dir=dir_name` instead of `--exclude-dir=folder/dir_name` which won't do the desired filtering. – Nagev May 30 '19 at 14:07
- 
                    1Would someone mind to explain this a little better? I need to exclude directories that are not subdirectories of the one I'm searching from. Say I write my `grep` command in `~/` and I need to exclude `/media` from the search. I don't think just writing `--exclude-dir=media` would do the trick, because it's not a subdirectory of `~/`. Am I wrong? Should I just `cd` into `/` (it seems odd to me)? – Andyc Apr 07 '21 at 20:43
- 
                    2@dkobozev I couldn't get it to work either. Had to use the following workaround instead: `grep -r keyword | grep -v 'public/dist'` – Krzysztof Wołowski Feb 23 '22 at 08:00
- 
                    
- 
                    @MatthewHerbst I use `EXCLUDE_NODEMODULES="--exclude-dir=node_modules --exclude-dir=.git"` in my .bashrc. So I use the same command every time (grep), but I type fast `grep $EXC-r ...` which is completed by bash to `grep --exclude... -r ...` – Gibezynu Nu Jan 18 '23 at 15:35
SOLUTION 1 (combine find and grep)
The purpose of this solution is not to deal with grep performance but to show a portable solution : should also work with busybox or GNU version older than 2.5.
Use find, for excluding directories foo and bar :
find /dir \( -name foo -prune \) -o \( -name bar -prune \) -o -name "*.sh" -print
Then combine find and the non-recursive use of grep, as a portable solution :
find /dir \( -name node_modules -prune \) -o -name "*.sh" -exec grep --color -Hn "your text to find" {} 2>/dev/null \;
SOLUTION 2 (using the --exclude-dir option of grep):
You know this solution already, but I add it since it's the most recent and efficient solution. Note this is a less portable solution but more human-readable.
grep -R --exclude-dir=node_modules 'some pattern' /path/to/search
To exclude multiple directories, use --exclude-dir as:
--exclude-dir={node_modules,dir1,dir2,dir3}
SOLUTION 3 (Ag)
If you frequently search through code, Ag (The Silver Searcher) is a much faster alternative to grep, that's customized for searching code. For instance, it automatically ignores files and directories listed in .gitignore, so you don't have to keep passing the same cumbersome exclude options to grep or find.
 
    
    - 3,782
- 4
- 16
- 33
 
    
    - 9,188
- 5
- 36
- 53
- 
                    3this combination searches faster than `--exclude-dir=dir` and it shows results with colors - easy to read – Maxim Yefremov Oct 08 '13 at 01:51
- 
                    32"this combination" `find ... -exec` is not faster than `grep --exclude-dir` for me. Huge advantage to grep (about five times faster with 26k+ files, filtered out of 38k+ on an HDD), unless you replace the `\;` with `+` for the find/exec combo. Then grep is "only" about 30% faster. The grep syntax is also human-readble :). – Kjell Andreassen Jan 27 '14 at 17:48
- 
                    Agreed, since this is obvious. Some busyboxes does not have the GREP command. – hornetbzz Feb 16 '18 at 12:57
- 
                    `grep --exclude-dir=dir -rin "text" .` works fine for me. `ag text .` (silver_searcher) works superb – user9869932 Oct 26 '18 at 11:10
- 
                    18also noting that you can exclude multiple with `--exclude-dir={dir1,dir2}` – suh Nov 07 '18 at 15:11
- 
                    10I'm not the least bit surprised that `node_modules` is the canonical example. – pdoherty926 Jan 16 '19 at 18:21
- 
                    
- 
                    
If you want to exclude multiple directories:
"r" for recursive, "l" to print only names of files containing matches and "i" to ignore case distinctions :
grep -rli --exclude-dir={dir1,dir2,dir3} keyword /path/to/search
Example : I want to find files that contain the word 'hello'. I want to search in all my linux directories except proc directory, boot directory, sys directory and root directory :
grep -rli --exclude-dir={proc,boot,root,sys} hello /
Note : The example above needs to be root
Note 2 (according to @skplunkerin) : do not add spaces after the commas in {dir1,dir2,dir3}
 
    
    - 1,785
- 1
- 13
- 10
- 
                    9**NOTE:** do not add spaces after the commas in `{dir1,dir2,dir3}` – skplunkerin Jan 30 '17 at 23:51
- 
                    Thanks, handy when grep'ing through SVN workspace: `grep -Irsn --exclude-dir=.svn 'foo' .` – RAM237 Aug 08 '17 at 15:41
- 
                    2
This syntax
--exclude-dir={dir1,dir2}
is expanded by the shell (e.g. Bash), not by grep, into this:
--exclude-dir=dir1 --exclude-dir=dir2
Quoting will prevent the shell from expanding it, so this won't work:
--exclude-dir='{dir1,dir2}'    <-- this won't work
The patterns used with --exclude-dir are the same kind of patterns described in the man page for the --exclude option:
--exclude=GLOB
    Skip files whose base name matches GLOB (using wildcard matching).
    A file-name glob can use *, ?, and [...]  as wildcards, and \ to
    quote a wildcard or backslash character literally.
The shell will generally try to expand such a pattern itself, so to avoid this, you should quote it:
--exclude-dir='dir?'
You can use the curly braces and quoted exclude patterns together like this:
--exclude-dir={'dir?','dir??'}
 
    
    - 3,650
- 2
- 16
- 15
If you are grepping for code in a git repository and node_modules is in your .gitignore, you can use git grep. git grep searches the tracked files in the working tree, ignoring everything from .gitignore
git grep "STUFF"
 
    
    - 3,782
- 4
- 16
- 33
 
    
    - 13,085
- 5
- 47
- 55
- 
                    
- 
                    This is an incredible way to limit wading through tons of generated files (dist, bin, etc.) and it pipes into a utility like `less` automagically so you have a scrollable search result. Fantastic! – Blake Neal May 10 '23 at 18:28
Frequently use this:
grep can be used in conjunction with -r (recursive), i (ignore case) and -o (prints only matching part of lines). To exclude files use --exclude and to exclude directories use --exclude-dir.
Putting it together you end up with something like:
grep -rio --exclude={filenames comma separated} \
--exclude-dir={directory names comma separated} <search term> <location>
Describing it makes it sound far more complicated than it actually is. Easier to illustrate with a simple example.
Example:
Suppose I am searching for current project for all places where I explicitly set the string value debugger during a debugging session, and now wish to review / remove. 
I write a script called findDebugger.sh and use grep to find all occurrences. However:
For file exclusions - I wish to ensure that .eslintrc is ignored (this actually has a linting rule about debugger so should be excluded). Likewise, I don't want my own script to be referenced in any results. 
For directory exclusions - I wish to exclude node_modules as it contains lots of libraries that do reference debugger and I am not interested in those results. Also I just wish to omit .idea and .git hidden directories because I don't care about those search locations either, and wish to keep the search performant.
So here is the result - I create a script called findDebugger.sh with:
#!/usr/bin/env bash
grep -rio --exclude={.eslintrc,findDebugger.sh} \
--exclude-dir={node_modules,.idea,.git} debugger .
 
    
    - 35,523
- 17
- 121
- 125
- 
                    
- 
                    1
- 
                    When I wrote [my answer](https://stackoverflow.com/a/8692318/78845), I used `-R` (I don't recall why now). I typically use `-r`. It turns out that the uppercase version [follows symlinks](https://git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c#n1968). TIL. – johnsyweb Apr 21 '20 at 06:56
- 
                    @Johnsyweb - thanks. upvoted your answer - don't recall when, likely in 2016 when I added this one :) – arcseldon Apr 22 '20 at 13:39
Many correct answers have been given here, but I'm adding this one to emphasize one point which caused some rushed attempts to fail before: exclude-dir takes a pattern, not a path to a directory.
Say your search is:
grep -r myobject
And you notice that your output is cluttered with results from the src/other/objects-folder. This command will not give you the intended result:
grep -r myobject --exclude-dir=src/other/objects-folder
And you may wonder why exclude-dir isn't working! To actually exclude results from the objects-folder, simply do this:
grep -r myobject --exclude-dir=objects-folder
In other words, just use the folder name, not the path. Obvious once you know it.
From the man page:
--exclude-dir=GLOB
Skip any command-line directory with a name suffix that matches the pattern GLOB. When searching recursively, skip any subdirectory whose base name matches GLOB. Ignore any redundant trailing slashes in GLOB.
 
    
    - 10,835
- 4
- 58
- 69
- 
                    2Why on the planet didn't I scroll down to this answer before I posted my comment/question up above? I unfortunately have the bad habit to ignore answers with less upvotes, but this explains what I was doing wrong, so thanks Nagev. – Andyc Apr 11 '21 at 06:04
- 
                    1I would go crazy because I used the full path to a subfolder, but it did not work. After I saw this comment, I used the folder name ONLY and it finally worked! THANKS – babis21 Apr 25 '23 at 14:18
You could try something like grep -R search . | grep -v '^node_modules/.*'
 
    
    - 5,470
- 2
- 20
- 24
- 
                    42Not such a good solution in some cases. For example: If 'node_modules' directory is a huge one with lots of false positive matches (hence the need to filter out the directory) then the first grep is wasting a lot of time searching through a sub-directory and THEN the second grep filtering out the matches. It's faster to exclude node_modules in the first grep itself. – GuruM Dec 13 '12 at 08:22
- 
                    2i don't care about the slowness, I can look at the command and know what it does – dansch Apr 22 '14 at 18:39
- 
                    1Ditto for Guru's comment. A grep of `/var` hangs when it hits `/var/run` in my case. Hence the reason I want to avoid the directory in the first place. – jww Aug 31 '15 at 09:48
- 
                    5
Very useful, especially for those dealing with Node.js where we want to avoid searching inside "node_modules":
find ./ -not -path "*/node_modules/*" -name "*.js" | xargs grep keyword
 
    
    - 30,738
- 21
- 105
- 131
 
    
    - 2,821
- 28
- 21
A simple working command:
root/dspace# grep -r --exclude-dir={log,assetstore} "creativecommons.org"
Above I grep for text "creativecommons.org" in current directory "dspace" and exclude dirs {log,assetstore}.
Done.
Step 1:
vim ~/.bash_profile
search() {
    grep -InH -r --exclude-dir=*build* -e "$1" .
}
Step 2:
source ~/.bash_profile
Usage:
search "<string_to_be_searched>"
 
    
    - 3,782
- 4
- 16
- 33
 
    
    - 4,080
- 1
- 37
- 48
This one works for me:
grep <stuff> -R --exclude-dir=<your_dir>
 
    
    - 25,404
- 19
- 49
- 81
 
    
    - 1,680
- 17
- 14
A simpler way would be to filter your results using "grep -v".
grep -i needle -R * | grep -v node_modules
 
    
    - 169
- 8
- 
                    15This is effectively the same answer DipSwitch provided 3 years earlier. It has the same problems, too. – jww Aug 31 '15 at 09:53
 
     
    