How to Conditionally Sum and Group Data with awk

A while back, I wrote a short, simple tutorial on how to sum a column from a file on the command line using nothing but awk. I even followed it up with a small script to calculate a running total, printing the result on each row.

Let’s take it a step further. What if you only want to sum column 3 when column 1 equals a specific value? Or what if you want the total for every unique value in column 1?

You can do this in a single awk line, with no other tools required.

The Setup

Imagine a file named fruit.txt containing the following sample data:

banana 2 14 9 1
cherry 11 4 7 15
apple 5 12 3 8
date 14 8 5 11
banana 15 4 8 10
apple 9 1 14 7
date 1 6 13 2
cherry 1 13 2 9
apple 2 11 6 13
cherry 8 6 10 12
banana 3 7 12 5
date 7 3 15 4
mango 1 2 6 3

The Conditional Sum

Let’s find the sum of column 3, but only where column 1 is “apple”:

awk '$1 == "apple" {sum+=$3} END {print sum}' fruit.txt

Here is exactly how this one-liner works:

  1. The Condition: awk evaluates $1 == "apple" first.
  2. The Action: If true, it adds the value of column 3 ($3) to the sum variable.
  3. The Result: Once the entire file is scanned, the END block prints the final total.

Why This Matters

It’s short, fast, and incredibly clean. On a typical modern machine, this command will process a 100 MB file (~1.5 million lines) in under a second.

Because modern awk implementations use dynamic memory allocation, your only real limit is your machine’s RAM. You can comfortably process text files up to 1GB (and often much larger) before hitting any performance bottlenecks.

The Grouped Sum: A Terminal Pivot Table

Next step, let’s see if we can do a sum and group the output based on the fruit. Instead of printing a number, we print each fruit with the sum of numbers in column 3 for that fruit.
Think of this as building a pivot table directly in your terminal.

To make this production-ready, let’s account for two common real-world conditions: the file, fruit.csv is comma-separated (.csv) and it contains a header row.

Fruit,Quantity,Price,Store_ID,Supplier_Code
banana,2,14,9,1
cherry,11,4,7,15
apple,5,12,3,8
date,14,8,5,11
banana,15,4,8,10
apple,9,1,14,7
date,1,6,13,2
cherry,1,13,2,9
apple,2,11,6,13
cherry,8,6,10,12
banana,3,7,12,5
date,7,3,15,4
mango,1,2,6,3
awk -F',' 'NR > 1{totals[$1] += $3} END {for (fruit in totals) print fruit, totals[fruit]}' fruit.csv

Let’s break this down.

  • -F',': Sets the field delimiter to commas instead of default white space.
  • NR > 1: Ensures awk skips the header row (Number of Records > 1) so it doesn’t try to add text labels to your math.
  • totals[$1]: This creates an associative array (think of it as a named “bucket”) based on the value in the first column (e.g., “apple”, “banana”).
  • += $3: This adds the value of the third column into that specific bucket. If the bucket doesn’t exist yet, awk quietly creates it and starts the count at zero.
  • END {for (fruit in totals) ...}: Once the entire file is scanned, this for-loop iterates through every bucket. It prints the bucket’s name (fruit) and the final accumulated sum stored inside it (totals[fruit]).

The output will look something like this:

mango 6
date 33
apple 32
banana 29
cherry 19

Note: awk does not guarantee the order of the output, which is why “mango” might appear first. If you need it sorted, you can simply pipe the result to sort

awk '{totals[$1] += $3} END {for (fruit in totals) print fruit, totals[fruit]}' fruit.txt |sort
apple 32
banana 29
cherry 19
date 33
mango 6

One line. No spreadsheet, no database, no extra dependencies.

Save pandas and NumPy for when you actually need a DataFrame. For this? awk just showed up and did the job.

Leave a Reply