How do I recursively view a list of files that has one string and specifically doesn't have another string? Also, I mean to evaluate the text of the files, not the filenames.
Conclusion:
As per comments, I ended up using:
find . -name "*.html" -exec grep -lR 'base\-maps' {} \; | xargs grep -L 'base\-maps\-bot'
This returned files with "base-maps" and not "base-maps-bot". Thank you!!
These answers seem off as the match BOTH strings. The following command should work better:
find . -maxdepth 1 -name "*.py" -exec grep -L "string-not-to-match" {} \;
This Command will get all ".py" files that don't contain "string-not-to-match" at same directory.
The use of xargs in the answers above is not necessary; you can achieve the same thing like this:
grep -q
means run quietly but return an exit code indicating whether a match was found;find
can then use that exit code to determine whether to keep executing the rest of its options. If-exec grep -q <string-to-match> {} \;
returns 0, then it will go on to execute-not -exec grep -q <string-not-to-match>{} \;
. If that also returns 0, it will go on to execute-print
, which prints the name of the file.As another answer has noted, using
find
in this way has major advantages overgrep -Rl
where you only want to search files of a certain type. If, on the other hand, you really want to search all files,grep -Rl
is probably quicker, as it uses onegrep
process to perform the first filter for all files, instead of a separategrep
process for each file.Here is a more generic construction:
This command outputs files whose name matches
<nameFilter>
(adjustfind
predicates as you need) which contain<patternYes>
, but do not contain<patternNo>
.The enhancements are:
If you don't need to filter by name (one often wants to consider all the files in current directory), you can strip
find
and add-R
to the firstgrep
:Try this:
Explanation:
grep -lr
makes grep recursively (r) output a list (l) of all files that contain<string-to-match>
. xargs loops over these files, callinggrep -L
on each one of them.grep -L
will only output the filename when the file does not contain<string-not-to-match>
.