awk sum a column: awk '{ s += $2 } END { print s }'
- tool
- awk
- versions
- GNU awk 5.x, mawk, BSD awk
- os
- linux, macos, windows
To add up a column of numbers, accumulate it in a variable for every line and print the variable in the END block: awk '{ s += $2 } END { print s }' file sums the second whitespace-separated field. Use -F, for comma-separated files and NR > 1 to skip a header line.
Sum one column
cat > sales.txt <<'EOF'
north 120
south 80
north 45.5
east 10
EOF
awk '{ s += $2 } END { print s }' sales.txtOutput
255.5
Variables in awk start as 0 (or the empty string), so s needs no initialisation. A non-numeric field counts as 0.
CSV with a header
cat > sales.csv <<'EOF'
region,amount
north,120
south,80
north,45.5
EOF
awk -F, 'NR > 1 { s += $2 } END { printf "%.2f\n", s }' sales.csvOutput
245.50
-F, sets the field separator, NR > 1 skips the first record, and printf "%.2f\n" fixes the number of decimals. Plain print uses the OFMT format (%.6g), which switches to exponent notation for large totals.
Totals per key
cat > sales.txt <<'EOF'
north 120
south 80
north 45.5
east 10
EOF
awk '{ t[$1] += $2 } END { for (k in t) print k, t[k] }' sales.txt | sortOutput
east 10 north 165.5 south 80
The array t is indexed by the first field. for (k in t) returns keys in no particular order, so pipe to sort for stable output.
Other variants
| Task | Command |
|---|---|
| Sum and count, average | awk '{ s += $2; n++ } END { if (n) print s / n }' file |
| Sum the last field | awk '{ s += $NF } END { print s }' file |
| Sum only matching lines | awk '/north/ { s += $2 } END { print s }' file |
| Sum a column from command output | du -sk * | awk '{ s += $1 } END { print s " KB" }' |
| Tab-separated input | awk -F'\t' '{ s += $3 } END { print s }' file.tsv |
Values that do not add up
awk converts a field to a number by reading its leading numeric part and ignoring the rest. Thousands separators, currency symbols and quotes therefore make values smaller or zero without any warning. Clean the field before adding it:
printf '1,200\n$5\n3\n' > amounts.txt
echo '--- raw sum (1,200 counts as 1, $5 as 0):'
awk '{ s += $1 } END { print s }' amounts.txt
echo '--- cleaned:'
awk '{ v = $1; gsub(/[$,]/, "", v); s += v } END { print s }' amounts.txt
echo '--- no input:'
: | awk '{ s += $1 } END { print "[" s "]", s + 0 }'Output
--- raw sum (1,200 counts as 1, $5 as 0): 4 --- cleaned: 1208 --- no input: [] 0
How to check the result
- Count the lines that were added with
n++next to the sum and compare it withwc -l(minus the header). A mismatch means a pattern orNR > 1skipped more than you thought. - Print suspicious values,
awk '$2 !~ /^-?[0-9.]+$/ { print NR": "$0 }' file, to find fields that are not plain numbers. - With a decimal comma (
45,5), awk reads45. Convert the comma first withsub(/,/, ".", $2)or export the data with a dot as decimal separator.
For printing a column instead of adding it, see awk print column; to count occurrences of values, see sort | uniq -c.
FAQ
Why does awk print an empty line instead of 0?
When no line was added, for example an empty file or a pattern that matched nothing, the variable was never assigned and prints as an empty string. Print s + 0 to force a number.
Why is my total too small?
awk reads only the leading numeric part of a field. A value like 1,200 counts as 1, and $5 or a quoted number counts as 0. Remove thousands separators, currency signs and quotes with gsub before adding.
How precise is the sum?
awk stores numbers as double-precision floating point, so integers are exact up to 2^53 and decimal amounts can show small rounding errors. Print with printf "%.2f" for money, or use gawk -M (arbitrary precision) when it is available.