Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I read the question about how to find out the number of files that contain a certain string. This is possible with grep -l "string" * | wc -l.

Is it possible to invert this, finding the number of files not containing the target string? I tried adding the -v option, but this doesn't seem to output the right result.

share|improve this question
add comment

5 Answers

up vote 6 down vote accepted

With GNU or OpenBSD grep:

grep -L "string" ./* | grep -c /
share|improve this answer
add comment

Another POSIX way:

c=0
for f in *; do
  [ -d "$f" ] && continue
  { grep -q string || c=$(($c + 1)); } < "$f"
done
echo "$c"

By redirecting the command group instead of grep alone, we avoid counting as 1 the files which we cannot open (like files which we don't have read permission for, or * if there's no non-hidden file in the current directory).

With GNU grep, the equivalent would be:

grep -d skip -L foo ./* | grep -c /

Note that you can't use wc -l as filenames can be made of several lines. Having ./ also avoids problems with filenames that start with - or are - (which -- doesn't work around). Note that it ignores dot files.

share|improve this answer
add comment

Here's a POSIX-compliant way, in case you don't have grep -L:

for file in *; do
    awk '/string/ { found=1; exit } END{ if(!found) { printf "x" } }' < "$file"
done | wc -c
share|improve this answer
add comment

Another POSIX way using only grep and wc:

COUNT_FILES=0
for i in *;do COUNT_FILES=$((COUNT_FILES+1));done
MATCHES=$(grep -l "string" * | wc -l)
NON_MATCHES=$((COUNT_FILES - MATCHES))
echo "There are $NON_MATCHES files not matching \"string\""
share|improve this answer
    
Note that it will return 1 if there's no non-hidden file in the current directory. You may also want to skip directories. Another way to count the files and avoid a race condition would be set -- *, use $# and loop with for i do .... You can't use wc -l to count files as filenames can be made of several lines. –  Stephane Chazelas Jan 8 at 12:47
add comment

Depending on how much files you want to search through, it's a good advice to take a look at ack-grep. The reason, because ack-grep is a lot faster than good'ol grep and the CLI is nearly identical.

ack-grep -Lur "some string" * | wc -l

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.