Tuesday, November 10, 2009

Sum of numbers in file - UNIX alternatives


Input file:

$ cat /tmp/file.txt
286
255564800
609
146
671290

Required: Add (Sum) all the numbers present in the above file.

Way#1: This is supposed to be the most popular way of doing an addition of numbers present in a particular field of a file.

$ awk '{s+=$0} END {print s}' /tmp/file.txt
256237131

Way#2: Using UNIX/Linux 'paste' command and 'bc'

$ paste -sd+ /tmp/file.txt
286+255564800+609+146+671290

$ paste -sd+ /tmp/file.txt | bc
256237131

Way#3: Using UNIX/Linux 'tr' command and 'bc'

$ tr -s '\n' '+' < /tmp/file.txt
286+255564800+609+146+671290+

$ echo $(tr -s '\n' '+' < /tmp/file.txt)
286+255564800+609+146+671290+

#Since there's an extra '+' at end of above output, echo an additional '0' like this
$ echo $(tr -s '\n' '+' < /tmp/file.txt)0
286+255564800+609+146+671290+0

$ echo $(tr -s '\n' '+' < /tmp/file.txt)0 | bc
256237131

Way#4: Same as above but doing the arithmetic without using 'bc'

$ printf "%d\n" $(( $(tr -s '\n' '+' < /tmp/file.txt) 0 ))
256237131

Way#5: Using sed and 'bc'

$ sed 's/$/+/' /tmp/file.txt
286+
255564800+
609+
146+
671290+

$ echo $(sed 's/$/+/' /tmp/file.txt) 0
286+ 255564800+ 609+ 146+ 671290+ 0

$ echo $(sed 's/$/+/' /tmp/file.txt) 0 | bc
256237131

Way#6 : or a basic bash script using for loop

sum=0
for num in $(cat /tmp/file.txt)
do
((sum+=num))
done
echo $sum

Way#7: Using python

>>> sum = 0
>>> lines = open("/tmp/file.txt", "r").readlines()
>>> lines
['286\n', '255564800\n', '609\n', '146\n', '671290\n']
>>> for line in lines:
... sum+=eval(line)
...
>>> sum
256237131

Related posts:

- 'Sum of' and 'group by' using awk
- Sum using awk substr function in bash
- Bash 'while loop' sum issue explained
- 'Exponential' value in awk sum output
- Python - adding numbers in a list

11 comments:

Unknown said...

One more python alternative:

>>> lines = open("/tmp/file.txt", "r").readlines()
>>> lines
['286\n', '255564800\n', '609\n', '146\n', '671290\n']
>>> lines = [int(line) for line in lines]
>>> lines
[286, 255564800, 609, 146, 671290]
>>> sum(lines)
256237131
>>> sum([int(line) for line in lines])
256237131
>>>

ps axu -o user | grep -i root said...

slightly different with python:

print(sum(map(int, open("/tmp/file.txt", "r").readlines())))

This work in one line and can be called from the command line with
python -c 'print(sum(map(int, open("/tmp/file.txt", "r").readlines())))'

Also you can omit the .readlines:
print(sum(map(int, open("/tmp/file.txt", "r"))))

will work.
Explanation:
open("file.txt", "r").readlines() creates a list with the lines

map(int, L) returns a new list with each of the elements converted to int
Finally
sum(map(int, L)) sum the elements of the list.

Unknown said...

@ps axu ... thanks a lot, its really useful explanation. Thanks again.

satish said...

hi jadu,
i am very happy to see your blog...all usefull things to me,i learnt from here,i got one more doubt..can u clear it.how to paste data to sheet2(sheet 1 already contains data) in csv using script or anymean...

Arun Prasaad said...

% perl -nE '$s += $_; say $s if eof' test.txt
256237131

ps axu -o user | grep -i root said...

Hi Arun,

your command line doesn't work for me... it says

perl -nE '$s += $_; say $s if eof' file.txt
Unrecognized switch: -E (-h will show valid options).

Unknown said...

-E option is valid for Perls 5.10 onwards and enables the optional features.

perl -alp0777e '$a += $_ for@F; $_ = $a'

Unknown said...

Another way is using the unix desk calculator,
set -- $(cat /tmp/file.txt)
n1=$1; shift
IFS=+
dc -e "$n1 $*$IFS p"

Unknown said...

set -- $(cat /tmp/file.txt)
echo "0 0$(printf ' %s+' ${1+"$@"})p" | dc

Unknown said...

if='/tmp/file.txt'

dc -e "
$(< $if tr '-' '_')
[+z2!>a]salaxp
"

Alternatively feeding stdin to "dc", we could do:
< $if tr '-' '_' |
dc -e "
[q]sq
[?z0=qla+salbx]sb
0salbxlap
"

Unknown said...

tr '-' '_' < /tmp/file.txt |
dc -e '[pq]sq[?z1=q+l?x]s?0dd=?'

© Jadu Saikia www.UNIXCL.com