Thursday, June 4, 2009

Remove files without match using bash grep


I have already discussed in one of my earlier post how we can find the files which do not contain a particular pattern (string).

As I mentioned in that particular post:

"Well, when I first heard of this requirement; I just thought I will use "grep -vl pattern" piped with xargs to a regular find command (i.e. "find . -type f | xargs grep -vl pattern")
(-l : Suppress normal output; instead print the name of each input file from which output would normally have been printed.)

Then I realized that "grep -v" only works in line level, i.e. a file which contain the "pattern" in some line(s) may also contain some line(s) which "do not" contain that "pattern"; so as a whole that file will also be in the list of files which "do not" contain the "pattern" even though it contains the pattern."

From GREP(1) man pages:

-L, --files-without-match
Suppress normal output; instead print the name of each input file from which no out-put would normally have been printed. The scanning will stop on the first match.

-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected. Also see the -s or --no-messages option.

So to remove or delete the files which do not contain the pattern or string "hello"

$ find . -type f -exec grep -L "hello" {} \; | xargs rm

or

$ find . -type f \! -exec grep -q "hello" {} \; -print | xargs rm

3 comments:

Mahesh said...

Nice one Saikia, I think we can do it inside find itself.
find . -type f -exec grep -L "hello" {} \; -exec rm {} \;

Jadu Saikia said...

Hey Mahesh, thanks for your comment. But that nested -exec as you mentioned does not work for me, I have tried that. Also do you have any idea how we can specify multiple(nested) operation to xargs ? Keep in touch. Thanks Again.

Mahesh said...

Do you have GNU find. This is a GNU feature ...
for nesting, this should be helpful

find -type f -print | xargs -I {} -i ksh -c 'cp {} /tmp; echo "{} copied to /tmp"'.

Not sure whether your xargs will support this, it worked for me.

© Jadu Saikia www.UNIXCL.com