9

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
  • 125,519
  • 44
  • 317
  • 399
Noah Duncan
  • 480
  • 5
  • 17
  • 2
    `--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
  • 5
    hmm, indeed. I have 2.15. Now, why info for --exclude-dir is included in the man page is beyond me. Tricksy. – Noah Duncan Nov 13 '13 at 20:17
  • Isn't `--exclude-dir` supposed to be used in conjunction with `-r` (recursive) ? – damienfrancois Nov 13 '13 at 20:23

2 Answers2

17

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
  • 2,924
  • 4
  • 26
  • 39
  • 5
    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
  • 1
    Wow, so not intuitive. Thank you for or this. – racl101 Oct 22 '18 at 19:08
  • 10
    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
8

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.
  • 102,141
  • 38
  • 210
  • 325