5

I have a file like this

1 4 7 ...
2 5 8
3 6 9 

And I would like to have as output

6 15 24 ...

That is the sum of all the lines for all the columns. I know that to sum all the lines of a certain column (say column 1) you can do like this:

awk '{sum+=$1;}END{print $1}' infile > outfile

But I can't do it automatically for all the columns.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
ayasha
  • 1,221
  • 5
  • 27
  • 46

6 Answers6

7

One more awk

awk '{for(i=1;i<=NF;i++)$i=(a[i]+=$i)}END{print}' file

Output

6 15 24

Explanation

{for (i=1;i<=NF;i++)         Set field to 1 and increment through

$i=(a[i]+=$i)                Set the field to the sum + the value in field

END{print}                   Print the last line which now contains the sums

As with the other answers this will retain the order of the fields regardless of the number of them.

  • you wind the minimal awk code solution! Good luck to all. – shellter Nov 24 '14 at 16:40
  • There's an SO for code golf. I don't find "minimal" code helpful when you're actually trying to solve a problem, and it puzzles me that it's seen as a good thing in awk. – rspeer Sep 21 '20 at 19:25
  • for some reason, this doesn't work on unix awk supplied with bsd. works using gawk (gnu awk) on these systems, – camelccc Mar 07 '23 at 14:45
5

You want to sum every column differently. Hence, you need an array, not a scalar:

$ awk '{for (i=1;i<=NF;i++) sum[i]+=$i} END{for (i in sum) print sum[i]}' file
6
15
24

This stores sum[column] and finally prints it.

To have the output in the same line, use:

$ awk '{for (i=1;i<=NF;i++) sum[i]+=$i} END{for (i in sum) printf "%d%s", sum[i], (i==NF?"\n":" ")}' file
6 15 24

This uses the trick printf "%d%s", sum[i], (i==NF?"\n":" "): print the digit + a character. If we are in the last field, let this char be new line; otherwise, just a space.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
5

There is a very simple command called numsum to do this:

numsum -c FileName

-c   ---    Print out the sum of each column.

For example:

cat FileName
1 4 7 
2 5 8
3 6 9 

Output :

numsum -c FileName
6 15 24

Note: If the command is not installed in your system, you can do it with this command:

apt-get install num-utils
fedorqui
  • 275,237
  • 103
  • 548
  • 598
Kalanidhi
  • 4,902
  • 27
  • 42
3
echo "1 4 7
2 5 8
3 6 9 " \
| awk '{for (i=1;i<=NF;i++){
   sums[i]+=$i;maxi=i}
 }
 END{
   for(i=1;i<=maxi;i++){
     printf("%s ", sums[i])
   }
 print}'

output

6 15 24

My recollection is that you can't rely on for (i in sums) to produce the keys any particular order, but maybe this is "fixed" in newer versions of gawk.

In case you're using an old-line Unix awk, this solution will keep your output in the same column order, regardless of how "wide" your file is.

IHTH

shellter
  • 36,525
  • 7
  • 83
  • 90
  • Instead of using maxi, you could just use NF :) –  Nov 24 '14 at 15:13
  • 1
    yes, tnx. The code could be significantly reduced in size, but my goal when writing answers is not the one-liner approach, but make it easier to understand for an awk beginner. (IMHO). – shellter Nov 24 '14 at 16:32
  • Thanks! I tried also using `for (i in sums)` but it gave me wrong results, instead in this way it works perfectly! – ayasha Nov 25 '14 at 09:42
0

AWK Program

#!/usr/bin/awk -f

{
    print($0);
    len=split($0,a);
    if (maxlen < len) {
        maxlen=len;
    }
    for (i=1;i<=len;i++) {
        b[i]+=a[i];
    }
}

END {
    for (i=1;i<=maxlen;i++) {
        printf("%s ", b[i]);
    }
    print ""
}

Output

1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
3 6 9 12 15 
Kannan Mohan
  • 1,810
  • 12
  • 15
-1

Your answer is correct. It is just missed to print "sum". Try this:

awk '{sum+=$1;} END{print sum;}' infile > outfile
Mohd
  • 138
  • 1
  • 10