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