Alright, I have two folders. For simplicity's sake, I'll call them people and animals. The animals folder has a file for each animal, and the people folder has a file for each person with references to which animals that person owns. This is what I have so far:

ls -1 ~/animals | cut -d. -f1 | grep -R -f - ~/people

The grep syntax I got from here. I'm trying to get it to say:

dog: 8
cat: 7
hippo: 2

Instead, I add the -c flag to grep and I get:

Bob.txt: 0
Cathy.txt: 0
John.txt: 0
Patrick.txt: 1

How do I get counts of the animals in total, not the animals for each person?

  • So you just want to add all the numbers obtained from grep output? – nitishch Apr 26 '15 at 5:19

Here’s a way to get the results you want with GNU awk:

awk '
        if (FILENAME ~ "^animals/"  ||  FILENAME ~ "/animals/") {
                this_name = substr(FILENAME, index(FILENAME,"animals/")+length("animals/"))
                i = index(this_name, ".")
                if (i > 0) this_name = substr(this_name, 1, i-1)
                critter[++num] = this_name
                critter_count[num] = 0
        for (i = 1; i <= num; i++) {
                if ($0 ~ critter[i]) critter_count[i]++
    END {
        for (i = 1; i <= num; i++) print critter[i] ": " critter_count[i]
'  animals/*  people/*
  • Upon starting a new file (BEGINFILE), check whether its name begins with animals/ or contains /animals/.  This lets you say animals/*, ./animals/*, or ~/animals/*.  If it does,

    • Extract the substring to the right of animals/.
    • Then look for a .; if found, extract the substring to the left of it.
    • Add this string (the base filename, with directory and extension removed) to the critter[] array, and initialize the corresponding critter_count to 0.

    ☛  Note that BEGINFILE and nextfile are not available in POSIX awk.

  • Otherwise (if we’re looking at a people file), loop through the animal names (critters) and count the lines that match them.
  • Upon reaching the END of all input, report the animal names that were extracted from the names of the animals files, and the counts of how often each appeared in a people file.

This won’t search the people directory recursively; I didn’t see any statement in the question that that was desired.


I think if you give the patterns as input to grep using stdin, it will concatenate results for all patterns. So AFAIK the only way to overcome this problem is to call a new instance of grep for each pattern.

This script would work in this case

for animalName in $(ls -1 ~/animals | cut -d. -f1);
        echo "$animalName: $(grep -R -h -c $animalName ~/people | paste -sd+ | bc)";

This is on the lines of what you have tried with some minor changes. First, -h option in grep suppresses printing of file names. Second, with just grep, output for a pattern would be like


We want to add all these numbers. paste command joins these lines with a + and then passes the formed string to bc to calculate the result.

NOTE: If your animal names contain newlines or any special characters (in some strange land), it is not advisable to parse the output of ls.

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.