Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unix Command to List files containing string but *NOT* containing another string

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

like image 843
Matrym Avatar asked Feb 14 '11 06:02

Matrym


People also ask

How do I find all files containing specific text in Unix?

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.

How do I find all files not containing specific text on Linux?

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.

How do you find files that do not contain a string?

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.


2 Answers

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

like image 52
Sander Marechal Avatar answered Sep 21 '22 22:09

Sander Marechal


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.

like image 34
Tom Avatar answered Sep 21 '22 22:09

Tom