Rgarg
Rgarg

Reputation: 506

Search presence of pattern in multiple files

I need to make sure that all the files which I find in a parent directory have a particular pattern or not. Example:

./a/b/status: *foo*foo
./b/c/status: bar*bar
./c/d/status: foo

The command should return false as file 2 does not have a foo. I am trying below but dont have clue on how to achieve this in single command.

find . -name "status" | xargs grep -c "foo"

Upvotes: 0

Views: 382

Answers (4)

Ed Morton
Ed Morton

Reputation: 203149

find . -name 'status' -exec grep -L 'foo' {} + | awk 'NF{exit 1}'

The exit status of the above will be 0 if all files contain 'foo' and 1 otherwise.

Upvotes: 0

Ali ISSA
Ali ISSA

Reputation: 408

You can count the number of files that do not contain "foo", if number> 0 it means that there is at least one file that does not contain "foo" :

find . -type f -name "status" | xargs grep -c "foo" | grep ':0$' | wc -l

or

find . -type f -name "status" | xargs grep -c "foo" | grep -c ':0$' 

or optimized using iamauser answer (thanks) :

grep -ir -c "foo" --include=status | grep -c ':0$'

if all files in the tree are named "status", you can use the more simple commande line :

grep -ir -c "foo"  | grep -c ':0$'

with check

r=`grep -ir -c foo  | grep -c ':0$'`
if [ "$r" != "0" ]; then
   echo "false"
fi

Upvotes: 1

ghoti
ghoti

Reputation: 46816

If you want find to output a list of files that can be read by xargs, then you need to use:

find . -name "status" -print0 | xargs -0 grep foo` to avoid filenames with special characters (like spaces and newlines and tabs) in them.

But I'd aim for something like this:

find . -name "status" -exec grep "foo" {} \+

The \+ to terminate the -exec causes find to append all the files it finds onto a single instance of the grep command. This is much more efficient than running grep once for each file found, which it would do if you used \;.

And the default behaviour of grep will be to show the filename and match, as you've shown in your question. You can alter this behaviour with options like:

  • -h ... don't show the filename
  • -l ... show only the files that match, without the matching text,
  • -L ... show only the files that DO NOT match - i.e. the ones without the pattern.

This last one sounds like what you're actually looking for.

Upvotes: 0

iamauser
iamauser

Reputation: 11469

-c option counts the number of times the pattern is found. You wouldn't need find, rather use -r and --include option for grep.

$ grep -r -c foo --include=status

-r does a recursive search for patterh foo for files that match status.

Example. I have four files in three directories. Each have a single line;

$ cat a/1.txt b/1.txt b/2.txt c/1.txt 
foobar
bar
foo
bazfoobar

With the above grep, you would get something like this,

$ grep -ir -c foo --include=1.txt
a/1.txt:1
b/1.txt:0
c/1.txt:1

Upvotes: 1

Related Questions