Reputation: 506
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
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
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
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
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