1

Bash command to check number of words in a file that contain letter “a”

14

Suppose that we have this test file:

$ cat file
the cat in the hat
the quick brown dog
jack splat

With grep implementations that have adopted GNU's -o extension, we can retrieve all the words containing a:

$ grep -wo '[[:alnum:]]*a[[:alnum:]]*' file
cat
hat
jack
splat

We can count those words:

$ grep -wo '[[:alnum:]]*a[[:alnum:]]*' file | wc -l
4
  • 1
    Personally I would consider using grep -c and would also use [aA] or the -i flag to ensure that words with an upper case A are also counted. – Steve Barnes Aug 2 '15 at 14:25
  • Adding -i for case-insensitivity is a good idea. -c counts the number of matching lines of input, not matching words in the output. For example, with the input file above, grep -woc '[[:alnum:]]*a[[:alnum:]]*' file returns 2 because there are two matching lines. By contrast, grep -wo '[[:alnum:]]*a[[:alnum:]]*' file | grep -c . would give the correct answer. Alternatively, @yaegashi's approach shows a good use of grep -c. – John1024 Aug 2 '15 at 19:49
8

POSIXly:

<file tr -s '[:space:]' '[\n*]' | grep -c a

Here, words are sequences of non-spacing characters.

5

Here's a Perl way:

 perl -0lnE 'say scalar grep(/a/,split(/\s/,$_));' file

And an awk way:

 awk '{for(i=1;i<=NF;i++){if($(i)~/a/){k++}}}END{print k}' file
  • 1
    Won't that just give you the number of a's in the file rather than the number of words containing a? – Colin 't Hart Aug 1 '15 at 19:01
  • @Colin'tHart um. Yes. Indeed it will. Thanks, no idea what I was thinking there. – terdon Aug 1 '15 at 19:24
1

With GNU grep:

 grep -oP '\b\w*a+\w*\b' file
1
awk 'BEGIN{RS="[[:space:][:punct:]]"; c=0}
     index($0,"a"){c++} 
     END{print c}'

Using a version of awk that supports multi-character Record Separator (RS), eg. GNU awk, you can cause awk to read one word per record.

Within that record, the index(in, string) function searches in for the first occurrence of string, and returns the 1-based character position of where it is found. If not found, index() returns 0. Thus the return value can be treated as a boolean condition test (0 = false, not zero = true). Note, this is not a regular expression search.

If a match is found, the variable c is incremented by 1 (c++)

The c=0 is required in the BEGIN{} block, for when c is never incremented - which would cause c to be null instead of 0. Another way to handle this issue would be to print 0+c (in the END{} block)

  • 2
    This relies on a version of awk that supports multi-character RS (e.g. GNU awk). I would probably put a + at the end of the pattern [[:space:][:punct:]]+ to match one or more characters and just use /a/{c++} (although I guess index might be marginally quicker). Some explanation would make your answer more useful. – Tom Fenech Aug 1 '15 at 14:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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