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%
Print the result properly
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
| Goal | Command |
|---|---|
| Sum | awk '{s+=$1} END {print s}' |
| Sum, skipping a header | awk 'NR>1 {s+=$1} END {print s}' |
| Average | awk '{s+=$1; n++} END {if (n) print s/n}' |
| Count | awk 'END {print NR}' |
| Max | `awk '{if (max=="" \ |
| Min | {% raw %}`awk '{if (min=="" \ |
| Sum per group | {% raw %}`awk '{s[$1]+=$2} END {for (k in s) print k, s[k]}' \ |
| Two decimals | {% raw %}printf "%.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.
Originally published on DEV Talk.
Top comments (0)