How to exclude some files not matching certain extensions with grep?

I'd use find to locate the files and pipe the result through xargs:

$ find . -type f \! -name "*~" \
                 \! -name "*.map" \
                 \! \( -name "*.js" -and \! -name "*.debug.js" \) \
         -print0 | xargs -0 grep "OK"

This searches for every file not matching "*~", "*.map" or "*.js but not *.debug.js".

Using find you can easily search for rather complex rules and this approach saves you from accidentally removing false positives as could happen with double grep.


I would just pass that through a second grep to remove them:

grep -r --exclude={\*~,\*.map} "OK" bar/ | grep -vP '(?<!debug)\.js'

The -v reverses the match, printing lines that don't match the pattern and the -P enables Perl Compatible Regular Expressions which let us use negative lookbehinds. This particular regex, will match .js that is not prececeded by debug which means (since we are inverting the matches) that only those .js files will be printed.

However, as @QuestionOverflow pointed out int the comments, that could have the unintended side effect of filtering out lines that contain OK and js since the grep -v is applied to the entire output, not only the file name. To avoid that, just add a colon (that's what grep uses to separate file names from file contents):

grep -r --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js:'

That will still fail if your input line contains foo.js: or if your file name contains :. So, to be sure, use a different approach:

grep -Tr --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js\t'

The -T causes grep to print a tab between the file name and the file contents. So, if we simply add a \t to the end of the regex, it will only match against file names, and not the contents of the line.

Still, using find might make more sense regardless.


With zsh you can do:

setopt extendedglob
grep OK some/dir/**/^(*~|*.map|(^*debug).js)

Provided of course the argument list isn't too long, in which case you can always do:

printf '%s\0' some/dir/**/^(*~|*.map|(^*debug).js) | xargs -0 grep OK

Tags:

Grep

Wildcards