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