Unix Command to List files containing string but *

2020-05-15 07:50发布

问题:

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!!

回答1:

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>.



回答2:

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.



回答3:

These answers seem off as the match BOTH strings. The following command should work better:

grep -l <string-to-match> * | xargs grep -c <string-not-to-match> | grep '\:0'


回答4:

Here is a more generic construction:

find . -name <nameFilter> -print0 | xargs -0 grep -Z -l <patternYes> | xargs -0 grep -L <patternNo>

This command outputs files whose name matches <nameFilter> (adjust find predicates as you need) which contain <patternYes>, but do not contain <patternNo>.

The enhancements are:

  • It works with filenames containing whitespace.
  • It lets you filter files by name.

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 first grep:

grep -R -Z -l <patternYes> | xargs -0 grep -L <patternNo>


回答5:

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.