2

I have a file that looks like this:

hello even evening how are they? ... 

I want to count the occurences of the letter e but without taking the letter e of the 1st field under consideration. I've used this command but it doesn't work.

awk 'for(i=2;i<=NR;i++) match($i,/e/){sum++}END{print sum}' 
1
  • awk uses a pattern { action } syntax. Whatever that for header does, you obviously intended to bracket the whole line in { .. }. Also "it does not work" is inadequate. What does it do, and what did you expect it to do? Commented Jan 4, 2020 at 15:19

5 Answers 5

5

With flexible gsub feature:

awk '{ $1=""; cnt += gsub("e", "") }END{ print cnt }' file 

The gsub() function returns the number of substitutions made

4
  • thank you so much! what if I wanted to count the occurrences of the letter e per line? Commented Jan 3, 2020 at 9:07
  • 1
    @user25, to print count per line - just use awk '{ $1=""; print gsub("e", "") }' file Commented Jan 3, 2020 at 9:09
  • how could I put the output of the command in a variable? inside the awk? Commented Jan 3, 2020 at 11:09
  • @user25 The same way you put the output of any command in a variable: var=$(awk ...) Commented Jan 3, 2020 at 18:08
3

Your loop looks correct apart from using NR (number of the current record/line) in place of NF (number of fields in the current record/line), but it would be easier to count with gsub():

$ awk '{ for (i=2; i<=NF; ++i) sum+=gsub("e","e",$i) } END { print sum }' file 6 

The gsub() function returns the number of times it makes a substitution.

In Perl, you would use the tr operator in a similar way

$ perl -ane 'shift @F; map($sum += tr/e/e/, @F); END { print $sum, "\n" }' file 6 

Or, you could just use the other basic utilities from the tool chest:

$ cut -d ' ' -f 2- file | tr -dc 'e' | wc -m 6 

This cuts off everything before the first space character, deletes everything that isn't an e, and then counts the number of characters that are left.

1

Some more approaches:

  1. coreutils

    $ cut -d' ' -f 2- file | fold -w1 | grep -c e 6 
  2. Perl (basically a golfed version of what Kusalananda gave)

    $ perl -lane 'map{$k+=tr/e//}@F[1..$#F];}{print $k ' file perl -lane 'map{$k+=s/e/e/g}@F[1..$#F]}{print $k' file 6 
  3. GNU grep + awk (just for fun)

    $ grep -oP '^\S+\K.*' file | awk -F'e' '{k+=NF-1}END{print k}' 6 
1

You could do this:

$ perl -lpe '/\S\s/g;$s+=()=/e/g}{print $s' file 6 
0
1
$ awk '{sum += gsub(/e/,"&") - gsub(/e/,"&",$1)} END{print sum+0}' file 6 
2
  • Is there any benefit in using gsub(/e/,"&") instead of gsub(/e/,"") or is it just habit, and general good practice? Commented Jan 4, 2020 at 0:43
  • @terdon In this case if I used "" instead of "&" in the first gsub() then there'd be no es left for the 2nd gsub() to count. I tend to always use "&" by default unless I need to remove the matched strings so I don't trip myself up if I need to print the original record or do anything else that requires the content to be as read. Commented Jan 4, 2020 at 2:47

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.