Skip to content

/commands/awk/awk-sum-column

awk sum a column: awk '{ s += $2 } END { print s }'

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · GNU Awk 5.4.1updated
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

bash
cat > sales.txt <<'EOF'
north 120
south 80
north 45.5
east 10
EOF
awk '{ s += $2 } END { print s }' sales.txt

Output

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

bash
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.csv

Output

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

bash
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 | sort

Output

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

TaskCommand
Sum and count, averageawk '{ s += $2; n++ } END { if (n) print s / n }' file
Sum the last fieldawk '{ s += $NF } END { print s }' file
Sum only matching linesawk '/north/ { s += $2 } END { print s }' file
Sum a column from command outputdu -sk * | awk '{ s += $1 } END { print s " KB" }'
Tab-separated inputawk -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:

bash
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 with wc -l (minus the header). A mismatch means a pattern or NR > 1 skipped 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 reads 45. Convert the comma first with sub(/,/, ".", $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.

Sources