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!!
Without a doubt, grep is the best command to search a file (or files) for a specific text. By default, it returns all the lines of a file that contain a certain string. This behavior can be changed with the -l option, which instructs grep to only return the file names that contain the specified text.
You can do it with grep alone (without find). grep -riL "somestring" . -L, --files-without-match each file processed. -R, -r, --recursive Recursively search subdirectories listed.
You want to use the "-L" option of grep : -L, --files-without-match Only the names of files not containing selected lines are written to standard output. Path- names are listed once per file searched. If the standard input is searched, the string ``(standard input)'' is written.
Try this:
grep -rl <string-to-match> | xargs grep -L <string-not-to-match>
Explanation: grep -lr
makes grep recursively (r) output a list (l) of all files that contain <string-to-match>
. xargs loops over these files, calling grep -L
on each one of them. grep -L
will only output the filename when the file does not contain <string-not-to-match>
.
The use of xargs in the answers above is not necessary; you can achieve the same thing like this:
find . -type f -exec grep -q <string-to-match> {} \; -not -exec grep -q <string-not-to-match> {} \; -print
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 over grep -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 one grep
process to perform the first filter for all files, instead of a separate grep
process for each file.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With