How about a nice bit of awk:
awk -v FS="" '{for(i=1; i<=NF; ++i) a[i]+=$i} END {for (i=1; i<=NF; ++i) printf "%d ", a[i] }' file
This creates an array a
that accumulates all of the sums for each digit. At the END
of the file, go through the array and print all of the sums.
The FS
variable is important here, as it means that each digit on the line is treated as a separate field.
Output:
12 12 13 11 15 19 23 12 12 8
update
The above code won't print a newline after the sums, which may be what you want. As suggested in the comments by fedorqui, one way round that would be to do:
awk -v FS="" '{for (i=1; i<=NF; ++i) a[i]+=$i} END {for (i=1; i<=NF; ++i) printf "%d%s", a[i], (i<NF?" ":"\n") }' file
Which prints a space between all of the values, then a newline at the end.
Alternatively, if you like concatenating strings, you could do:
awk -v FS="" '{for(i=1; i<=NF; ++i) a[i]+=$i} END{for (i=1; i<=NF; ++i) s=s a[i] " "; print s}' file
Which first builds up a string s
and then print
s it. print
will add the newline by default for you.
Inspired by choroba's answer, here's an alternative version using Perl:
perl -F'' -wane 'pop @F; $i=0; $s[$i++]+=$_ for @F }{ print "@s\n"' file
as in awk, set the field delimiter to ''
. Use the "autosplit" switch -a
which creates the array @F
, each element containing one digit.
The last element of @F
is the newline "\n"
, so pop
removes it. The array @s
keeps all of the sums in. The -n
switch means that the whole command is surrounded in while (<>) { ... }
, so using the }{
"eskimo operator" effectively creates an END
block. By setting the special variable $"
to a space $"
is a space by default, so the array can be printed in one go, with each element separated by a space.