views:

6914

answers:

20

I am looking for a command that will accept as input multiple lines of text, each line containing a single integer, and output the sum of these integers.

As a bit of background, I have a log file which includes timing measurements, so through grepping for the relevant lines, and a bit of sed reformatting I can list all of the timings in that file. I'd like to work out the total however, and my mind has gone blank as to any command I can pipe this intermediate output to in order to do the final sum. I've always used expr in the past, but unless it runs in RPN mode I don't think it's going to cope with this (and even then it would be tricky).

What am I missing? Given that there are probably several ways to achieve this, I'll be happy to read (and upvote) any approach that works, even if someone else has already posted a different solution that does the job.

Related question: Shortest command to calculate the sum of a column of output on Unix? (credits @Andrew)


Update: Wow, as expected there are some nice answers here. Looks like I'll definitely have to give awk deeper inspection as a command-line tool in general!

+10  A: 
perl -lne '$x += $_; END { print $x; }' < infile.txt
j_random_hacker
I've removed `-l` and `<`.
J.F. Sebastian
And I added them back: "-l" ensures that output is LF-terminated as shell `` backticks and most programs expect, and "<" indicates this command can be used in a pipeline.
j_random_hacker
You are right. As an excuse: Each character in Perl one-liners requires a mental work for me, therefore I prefer to strip as many characters as possible. The habit was harmful in this case.
J.F. Sebastian
No worries J.F. :)
j_random_hacker
+42  A: 

Bit of awk should do it?

awk '{s+=$1} END {print s}' mydatafile
Paul Dixon
very nice and compact, gotta love awk!
Jay
+1 for knowing i'm not the only awk fan left in the world. :)
roe
There's a lot of awk love in this room! I like how a simple script like this could be modified to add up a second column of data just by changing the $1 to $2
Paul Dixon
+1  A: 

You can do it in python, if you feel comfortable:

Not tested, just typed:

out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s

Sebastian pointed out a one liner script:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"
Tiago
python -c"from fileinput import input; print sum(map(int, input()))" numbers.txt
J.F. Sebastian
Or cat numbers.txt | python -c"from ...
J.F. Sebastian
Include above code in the answer if you like it.
J.F. Sebastian
cat is overused, redirect stdin from file:python -c "..." < numbers.txt
rjack
@rjack: `cat` is used to demonstrate that script works both for stdin and for files in argv[] (like `while(<>)` in Perl). If your input is in a file then '<' is unnecessary.
J.F. Sebastian
+1  A: 

Or use awk rather than sed : arithmetic sample

Aif
A: 

one simple solution would be to write a program to do it for you. This could probably be done pretty quickly in python, something like:

sum = 0
file = open("numbers.txt","R")
for line in file.readlines(): sum+=int(line)
file.close()
print sum

I haven't tested that code, but it looks right. Just change numbers.txt to the name of the file, save the code to a file called sum.py, and in the console type in "python sum.py"

Matt Boehm
calling readlines() reads the entire file into memory - using 'for line in file' could be better
orip
+4  A: 

The following works in bash:

I=0

for N in `cat numbers.txt`
do
    I=`expr $I + $N`
done

echo $I
Francisco Canedo
Command expansion should be used with caution when files can be arbitrarily large.With numbers.txt of 10MB, the `cat numbers.txt` step would be problematic.
rjack
Indeed, however (if not for the better solutions found here) I would use this one until I actually encountered that problem.
Francisco Canedo
+1  A: 

AWK has already been mentioned, so in addition I'd like to suggest that you use this language instead of GREP and SED for scanning the original log file. A suitable AWK script can easily do the job of both and calculate the interesting value as Paul and Alf have already pointed out.

Andreas Scherer
+8  A: 

The one-liner version in Python:

$ python -c "import sys; print sum(int(l) for l in sys.stdin)"
dF
Above one-liner doesn't work for files in sys.argv[], but that one does http://stackoverflow.com/questions/450799/linux-command-to-sum-integers-one-per-line#450825
J.F. Sebastian
True- the author said he was going to pipe output from another script into the command and I was trying to make it as short as possible :)
dF
Shorter version would be `python -c"import sys; print(sum(map(int, sys.stdin)))"`
J.F. Sebastian
+1  A: 

BASH solution, if you want to make this a command (e.g. if you need to do this frequently):

function addnums {
  TOTAL=0
  while read val; do
    TOTAL=$(($TOTAL+$val))
  done
  echo $TOTAL
}

Then usage:

cat /tmp/nums | addnums
Jay
+12  A: 

Plain bash:

$ cat numbers.txt 
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num ; do sum=$(($sum + $num)); done < numbers.txt ; echo $sum
55
rjack
heh. Looks familiar :-)
Jay
SO popped up something like "6 new answers have been posted while you tried to remember the correct syntax of bash while". One of those was yours, but I posted anyway. You earned my +1, though :D
rjack
+1  A: 

The following should work (assuming your number is the second field on each line).

awk 'BEGIN {sum=0} \
 {sum=sum + $2} \
END {print "tot:", sum}' Yourinputfile.txt
James Anderson
+2  A: 

You can using num-utils, although it may be overkill for what you need. This is a set of programs for manipulating numbers in the shell, and can do several nifty things, including of course, adding them up. It's a bit out of date, but they still work and can be useful if you need to do something more.

http://suso.suso.org/programs/num-utils/

sykora
+1  A: 

I think AWK is what you are looking for:

awk '{sum+=$1}END{print sum}'

You can use this command either by passing the numbers list through the standard input or by passing the file containing the numbers as a parameter.

Paolo
It's a dup: http://stackoverflow.com/questions/450799/linux-command-to-sum-integers-one-per-line#450821
J.F. Sebastian
+11  A: 

Or:

paste -sd+ infile|bc
radoulov
+1. How come I have been using Linux for over a decade and never heard of `paste`?
Thomas
khedron
A: 

This is very similar to a question I asked a while ago: http://stackoverflow.com/questions/295781/shortest-command-to-calculate-the-sum-of-a-column-of-output-on-unix

Andrew
A: 
dc -f infile -e '[+z1<r]srz1<rp'
Charles Bailey
A: 

$ sed 's/^/.+/' infile | bc | tail -1

A: 

I realize this is an old question, but I like this solution enough to share it.

% cat > numbers.txt
1 
2 
3 
4 
5
^D
% cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
15

If there is interest, I'll explain how it works.

Nym
Please don't. We like to pretend that -n and -p are nice semantic things, not just some clever string pasting ;)
hobbs
A: 
$ cat n
2
4
2
7
8
9
$ perl -MList::Util -le 'print List::Util::sum(<>)' < n
32

Or, you can type in the numbers on the command line:

$ perl -MList::Util -le 'print List::Util::sum(<>)'
1
3
5
^D
9

However, this one slurps the file so it is not a good idea to use on large files. See j_random_hacker's answer which avoids slurping.

Sinan Ünür
A: 

I had the same question and I tried all of the answers. But no solution could handle my input file (containing over 4 million lines) except of the awk one!

So, if your files ar biger, try AWK ;)

noob