Count number of elements that match one file with another using AWK

Viewed 127

First of all, thank you for your help. I have the file letter.txt:

 A
 B
 C

And I have the file number.txt

B  10
D  20
A  15
C  18
E  23
A  12
B  14

I want to count how many times does each letter in letter.txt appears in number.txt so the output will be:

We have found 2 A
We have found 2 B
We have found 1 C
Total letter found: 5

I know I can do it using this code, but I want to do it generally with any file.

cat number.txt | awk 'BEGIN {A=0;B=0;C=0;count=0}; {count++};{if ($1 == "A")A++};{if ($1 == "B")B++};{if ($1 == "C")C++}END{print "We have found" A "A\n" "We have found" B "B\n" "We have found" C "C"}
4 Answers

You basically want to do an inner join (easy enough to google) and group by the join key and return the count for each group.

awk 'NR==FNR { count[$1] = 0; next }
    $1 in count { ++count[$1]; ++total}
    END { for(k in count)
        print "We have found", count[k], k
    print "Total", total, "letters"}' letters.txt numbers.txt

All of this should be easy to find in a basic Awk tutorial, but in brief, the line number within the file FNR is equal to the overall line number NR when you are reading the first input file. We initialize count to contain the keys we want to look for. If we fall through, we are reading the second file; if we see a key we want, we increase its count. When we are done, report what we found.

Consider starting with:

$ join letter.txt <(cut -d' ' -f1 number.txt | sort) | uniq -c
      2 A
      2 B
      1 C

Then:

$ join letter.txt <(cut -d' ' -f1 number.txt | sort) | uniq -c |
    awk '
        { print "We have found", $1, $2; tot+=$1 }
        END { print "Total letter found:", tot+0 }
    '
We have found 2 A
We have found 2 B
We have found 1 C
Total letter found: 5

although in reality I'd probably just do it all in awk, just wanted to show an alternative.

Don't know if you need awk to me easier (but slower execution as you read in comments) to use grep -c

cat file1 | while read line; do 
  c=`grep -c $line file2 | sed 's/ //g'`; 
  echo We have found $c $line; 
done

it's a cycle, where $c is the count taken with grep -c, and sed remove spaces in grep -c output

grep and coreutils can also do this:

grep -f letter.txt number.txt | cut -d' ' -f1 | sort | uniq -c

Output:

      2 A
      2 B
      1 C
Related