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 am trying to run the find command to find the total number of occurrences of a particular text string and also the number of files which has this text string.

What I have right now is this command.

find . -name "*.txt" | xargs grep -i "abc"

This reports all the "*.txt" files which contain the text "abc". I want either one or two find command to get

  1. Total number of times abc appears
  2. Total number of files which has abc in it.
share|improve this question
1  
for the sake of precision: your command (and all the other grep based solutions) do not display the number of occurrences of the text string but the number of lines where the string occurres at least once –  miracle173 May 4 '12 at 17:40
    
@miracle173 Good point! –  SigueSigueBen May 4 '12 at 18:41
add comment

4 Answers

up vote 2 down vote accepted

For question 1, you can do this:

find . -name "*.txt" | xargs grep -i "abc" | wc -l

This counts the total number of matches for abc in all text files.

And for question 2, I came up with:

find . -name "*.txt" -exec grep -i "abc" {} + | cut -d: -f1 | sort | uniq | wc -l

This gets just the unique filenames from the list of matches and counts them (the sort is probably not needed).


As pointed out by miracle173, grep comes with a "one match per file" flag so the command can be shortened to just:

find . -name "*.txt" -exec grep -il "abc" {} + | wc -l

share|improve this answer
2  
2. is a little bit complicated. grep -l will display one line for each file containing the search string. –  miracle173 May 4 '12 at 6:01
    
@SigueSigueBen Thanks for your answer. The first one works but for the second one looks like you are missing something after wc -. I am getting this error wc: cannot open - find: bad option out –  Nomad May 4 '12 at 15:55
    
@Nomad There was a missing character at the end. –  SigueSigueBen May 4 '12 at 16:01
    
@miracle173 I'm not surprised there's a shorter answer. I didn't know about grep -l to be honest. I've updated my answer. –  SigueSigueBen May 4 '12 at 16:04
    
Guys thanks to everyone, who contributed to this question, for your time and help. I will tryout the suggestions and will come back here with update. –  Nomad May 4 '12 at 18:19
show 2 more comments

grep's -c option is what you need here

find . -name \*txt | xargs grep -c -i "abc" | {
    total=0
    count=0 
    while IFS=: read name num; do 
        ((num > 0)) && ((count+=1))
        ((total+=num))
    done
    echo total=$total 
    echo count=$count
}

The braces to group the commands around the while loop are required to keep the variables in one scope for that subshell.

share|improve this answer
    
Thanks for your answer. –  Nomad May 4 '12 at 18:17
    
countcontains the number of files found by find . -name \*txt and not the number files containing the string because grep -c returng 0 if the string is not found in a file. –  miracle173 May 5 '12 at 4:03
    
@miracle173, quite right. answer updated. –  glenn jackman May 5 '12 at 11:49
    
@glenn jackman, your solution is very elegant and one stop approach. I like it. Plus it works :). –  Nomad May 8 '12 at 3:30
    
@glenn jackman, your solution is great but for sometimes i was getting error for it, otherwise i would have accepted your answer. But thank you so much for your help and answer, really appreciate it. –  Nomad Aug 5 '12 at 2:13
show 1 more comment
$ grep -R --include='*.txt' -c -i abc . | awk -F: ' 
           BEGIN {
                    totalCount=0;noOfFiles=0;
                 } 
                 { totalCount=totalCount+$2; 
                   if ( $2 > 0 ) 
                   {
                       noOfFiles+=1;
                   } 
                 } 
            END {
             print "Total number of times abc appears:"totalCount; 
             print "Total number of files which has abc in it:"noOfFiles
            } '

(OR)

ls output should not be used to parsed by other programs. See the comment below.

$  ls -Rltr | awk '/.txt/{print $NF }' | xargs grep -c -i "abc" | awk -F: ' 
       BEGIN {
                totalCount=0;noOfFiles=0;
             } 
             { totalCount=totalCount+$2; 
               if ( $2 > 0 ) 
               {
                   noOfFiles+=1;
               } 
             } 
        END {
         print "Total number of times abc appears:"totalCount; 
         print "Total number of files which has abc in it:"noOfFiles
        } '


Result:
Total number of times abc appears:0
Total number of files which has abc in it:0
share|improve this answer
    
Thanks for your answer. –  Nomad May 4 '12 at 18:17
1  
This command won't find text files in subdirectories (unless the directory has a .txt extension). –  SigueSigueBen May 4 '12 at 18:22
    
@SigueSigueBen My bad, fixed it. Thanks! –  user14039 May 4 '12 at 19:25
    
The answer that relies on ls -R doesn't work (the output of ls -R is not full paths! And retaining only the last word does nothing, except further mangle file name with spaces), and you shouldn't parse the output of ls anyway. –  Gilles May 4 '12 at 22:56
    
@anon_anon, i tried your both commands and they don't work. grep: illegal option -- R grep: illegal option -- include=*.txt Usage: grep -hblcnsviw pattern file . . . awk: syntax error near line 2 awk: bailing out near line 2 –  Nomad May 7 '12 at 2:03
show 2 more comments

Number of abc's contained in files:

To count the number of all "abc"'s in the .txt files, use grep -c and find and - exceptionally - cat:

find . -name "*.txt" -exec cat {} + | grep -ic abc

Grep -c will do the total count for you - something I didn't find in SigueSigueBen's answer, which contains unjustified calls to xargs, imho. The other 2 answers where to long for me. I didn't study them and wouldn't write such things myself.

Number of files containing abc:

find . -name "*.txt" -exec grep -iq abc {} ";" -printf "1" | wc -c 

This will not fail with filenames (which are rarely, I admit) containing newlines in their name (which is perfectly legal).

share|improve this answer
    
thank you for your answer. –  Nomad Aug 5 '12 at 2:14
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.