Skip to content

AWK Sum Column: Total, Average, Min, Max and Group By

How to sum a column with AWK, plus average, min, max and totals per group. Handles headers, empty files and messy data. Examples tested on gawk and mawk.

Dasun Kalupahana 5 min read 73 views 0 comments
On this page
  1. The quick answer
  2. Sample files
  3. Sum a column
  4. Count rows and calculate the average
  5. Guard against an empty file
  6. Minimum and maximum
  7. Sum only some rows
  8. Totals per group
  9. Sum across each row, or down each column
  10. Running total
  11. Percent of total (reading the file twice)
  12. Print the result properly
  13. When the data is messy
  14. Text where a number should be
  15. Currency symbols and thousand separators
  16. Numbers with a unit
  17. Strings that look like hex
  18. Quick reference
  19. Frequently asked questions
  20. How do I sum a column in AWK?
  21. How do I sum a column in a CSV file?
  22. Why does my total print as 1.23457e+06?
  23. Can AWK sum a column that has a header?

Adding up a column of numbers is one of the best reasons to learn AWK. There is no spreadsheet to open and no script to write: one line reads the file, adds each value to a running total, and prints the result at the end. This guide starts with that one line and then covers the things people actually need next: average, minimum and maximum, totals per group, and what to do when the data is messy. Every example comes with the input and the exact output.

The quick answer

awk '{sum += $1} END {print sum}' numbers.txt                # sum of column 1
awk -F, 'NR>1 {sum += $4} END {print sum}' sales.csv         # CSV: skip header, sum column 4

New to AWK? The beginner's guide explains the pattern {action} idea used here, and how to print a column explains $1, $4 and NR.

Sample files

printf '10\n20\n30.5\n' > nums.txt
printf '100\n9\n25\n' > n3.txt
printf '5\nN/A\n7\n' > bad.txt
printf '1 2 3\n4 5 6\n' > grid.txt
: > empty.txt        # an empty file

cat > sales.csv <<'EOF'
date,region,product,qty,price
2026-10-01,north,pen,10,1.50
2026-10-01,south,book,3,12.00
2026-10-02,north,book,2,12.00
2026-10-02,east,pen,25,1.50
2026-10-03,south,pen,5,1.50
EOF

Sum a column

awk '{sum += $1} END {print sum}' nums.txt
# 60.5

Here is what happens. For every line, sum += $1 adds the first field to sum. You never declared sum: AWK creates a variable the first time you use it and starts it at zero. The END block runs once, after the last line, and prints the total.

For a CSV with a header, add -F, for the separator and NR>1 to skip the header line:

awk -F, 'NR>1 {s += $4} END {print s}' sales.csv
# 45

Leaving out NR>1 does not change this total, because the header text qty counts as 0. But it quietly breaks the next calculation.

Count rows and calculate the average

Keep a counter next to the sum, then divide at the end:

awk -F, 'NR>1 {s += $4; n++} END {print s, n, s/n}' sales.csv
# 45 5 9

Now see what happens without the header skip:

awk -F, '{s += $4; n++} END {print s, n, s/n}' sales.csv
# 45 6 7.5

The sum is the same, but the header was counted as a sixth row, so the average is wrong and nothing warns you.

Guard against an empty file

If there is no input, n is never set, and the division goes wrong. The two awks I tested disagree on how:

awk '{s += $1; n++} END {print s/n}' empty.txt
# gawk: fatal: division by zero attempted
# mawk: -nan

gawk stops with an error. mawk prints -nan and carries on, which is easy to miss in a script. Check before you divide:

awk '{s += $1; n++} END {if (n > 0) print s/n; else print "no data"}' empty.txt
# no data

Minimum and maximum

Start both from the first data row, then compare every row against them:

awk -F, 'NR==2 {min=max=$4}
         NR>2  {if ($4<min) min=$4; if ($4>max) max=$4}
         END   {print "min", min, "max", max}' sales.csv
# min 2 max 25

The comparison is numeric, not alphabetical. On the file n3.txt (100, 9, 25), the minimum comes out as 9 and the maximum as 100, which is correct. If the comparison were on text, "9" would beat "100".

Do not start the minimum at 0 in a BEGIN block. Then nothing in a list of positive numbers is ever smaller, and you get 0:

awk 'BEGIN{min=0} {if ($1<min) min=$1} END {print min}' n3.txt
# 0   (wrong, the real minimum is 9)

If the data may not have a header, or you do not know the first row's line number, use a version that treats "not set yet" as the starting point:

awk '{if (min=="" || $1<min) min=$1; if (max=="" || $1>max) max=$1} END {print min, max}' n3.txt
# 9 100

Sum only some rows

Put a condition in front of the braces. Total quantity sold in the north region:

awk -F, '$2=="north" {s += $4} END {print s}' sales.csv
# 12

To count matching rows, use a counter. Add +0 when you print it, so that zero matches prints 0 instead of an empty line:

awk -F, 'NR>1 && $2=="north" {n++} END {print n+0}' sales.csv
# 2

Totals per group

An array indexed by the group name gives you one total per group. This is the AWK version of a spreadsheet pivot table:

awk -F, 'NR>1 {s[$2] += $4} END {for (k in s) print k, s[k]}' sales.csv | sort
# east 25
# north 12
# south 8

The | sort is there because AWK does not promise any order when looping over an array; gawk and mawk printed the same groups in a different order when I left it out.

The same idea works for money. Revenue is quantity times price, so add that product per region, plus a grand total:

awk -F, 'NR>1 {r[$2] += $4 * $5; t += $4 * $5}
         END {for (k in r) print k, r[k]; print "total", t}' sales.csv | sort
# east 37.5
# north 39
# south 43.5
# total 120

Sum across each row, or down each column

The file grid.txt has two lines of three numbers. A loop over the fields gives the total of each row:

awk '{t=0; for (i=1; i<=NF; i++) t += $i; print t}' grid.txt
# 6
# 15

To total every column at once, keep an array indexed by column number:

awk '{for (i=1; i<=NF; i++) c[i] += $i}
     END {for (i=1; i<=NF; i++) printf "%s%s", c[i], (i<NF ? OFS : ORS)}' grid.txt
# 5 7 9

Inside END, NF still holds the field count of the last line, which is fine when every line has the same number of columns.

Running total

Print inside the main rule, not in END, to show the total so far on every line:

awk -F, 'NR>1 {s += $4; print $4, s}' sales.csv
# 10 10
# 3 13
# 2 15
# 25 40
# 5 45

Percent of total (reading the file twice)

To show each row as a share of the total, AWK needs the total first. Pass the same file twice. NR==FNR is true only while the first copy is being read, so you can add things up on the first pass and print on the second:

awk -F, 'NR==FNR { if (FNR>1) t += $4; next }
         FNR>1  { printf "%-5s %5.1f%%\n", $3, $4/t*100 }' sales.csv sales.csv
# pen    22.2%
# book    6.7%
# book    4.4%
# pen    55.6%
# pen    11.1%

AWK's plain print shows a number with at most six significant digits, so a large decimal total turns into scientific notation. I tested this on both awks:

awk 'BEGIN {print 1234567.89; printf "%.2f\n", 1234567.89}'
# 1.23457e+06
# 1234567.89

For money and anything you plan to copy into a report, use printf "%.2f\n". Whole numbers are fine either way (100000 * 3 prints 300000), and 0.1 + 0.2 prints 0.3 because of the same six-digit rounding.

When the data is messy

Text where a number should be

AWK converts text to the number it starts with, and to 0 if it starts with no number. A row of N/A is added as 0, with no error:

awk '{s += $1; n++} END {print s, n, s/n}' bad.txt
# 12 3 4

The sum is right, but the average divides by three rows when only two have numbers. Filter with a pattern, and the count and the sum both agree:

awk '$1 ~ /^[0-9.]+$/ {s += $1; n++} END {print s, n, s/n}' bad.txt
# 12 2 6

Currency symbols and thousand separators

A value like $1,200.50 starts with a dollar sign, so AWK reads it as 0. Strip the symbol and the comma first with gsub:

printf 'price\n$1,200.50\n$99.25\n' > money.txt
awk '{s += $1} END {print s}' money.txt
# 0

awk 'NR>1 {gsub(/[$,]/, "", $1); s += $1} END {printf "%.2f\n", s}' money.txt
# 1299.75

(I skipped the price header with NR>1; it would add 0 either way.) A comma used as a thousands separator also clashes with -F,. A quoted "1,200" in a CSV file is split into two fields, which is a job for the CSV article in this series.

Numbers with a unit

AWK reads the leading number and ignores the rest, so 20G plus 120G adds to 140:

printf 'Used\n20G\n0\n120G\n' | awk 'NR>1 {s += $1+0} END {print s}'
# 140

That works only when every value has the same unit. A column that mixes M and G will add the digits as if they were the same thing.

Strings that look like hex

One difference between the two awks: a value such as 0x1A is 0 in gawk and 26 in mawk when used as a number. If your data contains hex-looking codes, do not rely on arithmetic on them.

Quick reference

GoalCommand
Sumawk '{s+=$1} END {print s}'
Sum, skipping a headerawk 'NR>1 {s+=$1} END {print s}'
Averageawk '{s+=$1; n++} END {if (n) print s/n}'
Countawk 'END {print NR}'
Maxawk '{if (max=="" || $1>max) max=$1} END {print max}'
Minawk '{if (min=="" || $1<min) min=$1} END {print min}'
Sum per groupawk '{s[$1]+=$2} END {for (k in s) print k, s[k]}' | sort
Two decimalsprintf "%.2f\n", s

Frequently asked questions

How do I sum a column in AWK?

Add each value to a variable in the main rule and print it in END: awk '{s += $3} END {print s}' file.

How do I sum a column in a CSV file?

Add the separator and skip the header: awk -F, 'NR>1 {s += $4} END {print s}' file.csv.

Why does my total print as 1.23457e+06?

Plain print limits numbers to six significant digits. Use printf "%.2f\n", total.

Can AWK sum a column that has a header?

Yes. Skip the first line with NR>1, so the header is neither added nor counted.

Free resources for this topic

Code snippets and fixes for this topic

Get one practical tip every week

New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.

Have a question about this post?

Ask the community: other developers and the author can answer.

Ask the community

Get notified about new articles

One click, no email needed. Turn it off anytime with the bell at the top.

Get new articles on your iPhone

Add DEV Talk to your Home Screen, open it, then tap the bell.

Rate this post
0.0
Share

Enjoying the content?

If this article helped you, you can support the author with a coffee. It keeps new posts coming.

Buy me a coffee (opens in a new tab)

Comments 0

Be kind. Comments with links are reviewed before they appear.

No comments yet

Be the first to share your thoughts.

Get new articles in your inbox

Practical tutorials and deep dives, about once a week. No spam, unsubscribe anytime.

Privacy policy

Add DEV Talk to your Home Screen

  1. 1 Tap the Share button in Safari's toolbar.
  2. 2 Scroll down and tap Add to Home Screen.
  3. 3 Tap Add. Open it from the Home Screen to read like an app and to turn on notifications with the bell.

We use cookies to improve your experience and analyze traffic. By continuing, you agree to our Privacy Policy.