Shortest command to calculate the sum of a column of output on Unix?

I know this question is somewhat dated, but I can't see "my" answer here, so I decided to post nonetheless. I'd go with a combination of

  • tail (to get the lines you need)
  • tr (to shrink down multiple consequitive spaces to one)
  • cut (to get only the needed column)
  • paste (to concatenate each line with a + sign)
  • bc (to do the actual calculation)

ipcs doesn't give an output on my system, so I'll just demo it with df:

# df
Filesystem     1K-blocks    Used Available Use% Mounted on
rootfs          33027952 4037420  27312812  13% /
udev               10240       0     10240   0% /dev
tmpfs             102108     108    102000   1% /run
/dev/xvda1      33027952 4037420  27312812  13% /
tmpfs               5120       0      5120   0% /run/lock
tmpfs             204200       0    204200   0% /run/shm
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web1/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web2/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web3/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client1/web4/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client2/web5/log
/dev/xvda1      33027952 4037420  27312812  13% /var/www/clients/client2/web6/log
# df | tail -n +2 | tr -s ' ' | cut -d ' ' -f 2 | paste -s -d+ | bc
264545284

I know doing this particular calculation on my system doesn't really make sense, but it shows the concept.

All of the pieces of this solution have been shown in the other answers, but never in that combination.


I have a utility script which simply adds up all columns. It's usually easy enough to grab the one you want from the one-line output. As a bonus, some SI-suffixes are recognized.

#!/usr/bin/awk -f
# Sum up numerical values by column (white-space separated)
#
# Usage:  $0 [file ...]
#
# stern, 1999-2005

{
    for(i = 1; i <= NF; ++i) {
        scale = 1
        if ($i ~ /[kK]$/) { scale = 1000 }
        if ($i ~ /[mM]$/) { scale = 1000*1000 }
        if ($i ~ /[gG]$/) { scale = 1000*1000*1000 }
        col[i] += scale * $i;
    }
    if (NF > maxnf) maxnf = NF;
}

END {
    for(i = 1; i <= maxnf; ++i) { printf " %.10g", col[i] }
    print "";
}

Example with custom field separator:

$ head /etc/passwd | addcol -F:
0 0 45 39 0 0 0

ipcs -mb | tail +4 | awk '{ sum += $7 } END { print sum }'

Or without tail:

ipcs -mb | awk 'NR > 3 { sum += $7 } END { print sum }'

Using awk with bc to have arbitrary long results (credits to Jouni K.):

ipcs -mb | awk 'NR > 3 { print $7 }' | paste -sd+ | bc

I would try to construct a calculation string and feed it to bc as follows:

  1. grep the lines that contain the numbers
  2. sed away all characters before (and after) the number on each line
  3. xargs the result (to get a string of numbers separated by blanks)
  4. tr anslate the blanks to '+' characters
  5. good appetite bc!

ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | bc

Looks like this is slightly longer than the awk solution, but for everyone who can't read (and understand) the odd awk code this may be easier to grasp... :-)

If bc is not installed you can use double parentheses in step 5 above to calculate the result:

  • echo $(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) )) or
  • SUM=$(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) )) or
  • (( SUM=$(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) ))

The spacing after and before the double parentheses is optional.

Tags:

Unix

Shell

Math

Ksh