10

I have the following function defined in my .bashrc, but for some reason the --exclude-dir option is not excluding the .git directory. Can anyone see what I've done wrong? I'm using Ubuntu 13.10 if that helps.

function fif # find in files
{
  pattern=${1?"  Usage: fif <word_pattern> [files pattern]"};
  files=${2:+"-iname \"$2\""};

  grep "$pattern" --color -n -H -s $(find . $files -type f) --exclude-dir=.git --exclude="*.min.*"
  return 0;
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Noah Duncan
  • 500
  • 1
  • 5
  • 18
  • 3
    `--exclude-dir` option is only available in recent versions of GNU grep (>= 2.5.2) - [reference](http://stackoverflow.com/a/8692318/526471). You may find [this answer](http://stackoverflow.com/a/6565519/526471) helpful – jkshah Nov 13 '13 at 20:11
  • Isn't `--exclude-dir` supposed to be used in conjunction with `-r` (recursive) ? – damienfrancois Nov 13 '13 at 20:23

2 Answers2

18

Make sure not to include a trailing slash when you specify the directory to exclude. For example:

Do this:

$ grep -r --exclude-dir=node_modules firebase .

NOT this:

$ grep -r --exclude-dir=node_modules/ firebase .

(This answer not applicable to OP, but may be helpful for others who find --exclude-dir not to be working -- it worked for me.)

dinosaur
  • 3,164
  • 4
  • 28
  • 40
  • 6
    Absolute paths seem to be a no-no as well. I was searching from root and wanted to avoid `/dev`, `/proc`, `/sys`, etc. `--exclude-dir=/dev` didn't work whereas `--exclude-dir=dev` worked as expected. – Scott Smith Jan 02 '18 at 18:57
  • 12
    This is because --exclude-dir only matches on basenames. This means that referring to a nested folder won't work either, e.g. --exclude-dir=mydir/node_modules should be --exclude-dir=node_modules. See here: https://superuser.com/a/1096219 – Galen Long May 23 '19 at 15:36
  • also watch out for typos not only in the trailing slash, but due to grep output eg outputting current dir ./snap/, not putting a dot in the beginning of location when its not a hidden one – FantomX1 Feb 13 '23 at 08:03
11

Do a man grep on your system, and see what version you have. Your version of grep may not be able to use --exclude-dirs.

You're really better off using find to find the files you want, then use grep to parse them:

$ find . -name '.git' -type d -prune \
     -o -name "*.min.*" -prune \
     -o -type f -exec grep --color -n -H {} "$pattern" \;

I'm not a fan of the recursive grep. Its syntax has become bloated, and it's really unnecessary. We have a perfectly good tool for finding files that match a particular criteria, thank you.

In the find program, the -o separate out the various clauses. If a file has not been filtered out by a previous -prune clause, it is passed to the next one. Once you've pruned out all of the .git directories and all of the *.min.* files, you pass the results to the -exec clause that executes your grep command on that one file.

Some people prefer it this way:

$ find . -name '.git' -type d -prune \
     -o -name "*.min.*" -prune \
     -o -type f -print0 | xargs -0 grep --color -n -H "$pattern"

The -print0 prints out all of the found files separated by the NULL character. The xargs -0 will read in that list of files and pass them to the grep command. The -0 tells xargs that the file names are NULL separated and not whitespace separated. Some xargs will take --null instead of the -0 parameter.

David W.
  • 105,218
  • 39
  • 216
  • 337