16

Each line contains text and numbers in one column. I need to calculate the sum of the numbers in each row. How can I do that? Thx

example.log contains:

time=31sec time=192sec time=18sec time=543sec 

The answer should be 784

2
  • I tried this method awk '{ sum += $1}; END { print sum }' example.log but it's only for numbers in line Commented May 27, 2015 at 18:13
  • 2
    There is almost the same question in Stack Overflow: How can I quickly sum all numbers in a file?. Maybe time to have cross-site duplicates? Commented May 28, 2015 at 7:26

10 Answers 10

18

If your grep support -o option, you can try:

$ grep -o '[[:digit:]]*' file | paste -sd+ - | bc 784 

POSIXly:

$ printf %d\\n "$(( $(tr -cs 0-9 '[\n*]' <file | paste -sd+ -) ))" 784 
0
16

With a newer version (4.x) of GNU awk:

awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}' 

With other awks try:

awk -F '[a-z=]*' '{s+=$2}END{print s}' 
2
  • 4
    You need s+0 in case where s is empty, it will print 0 instead of empty. Commented May 27, 2015 at 18:20
  • Let me explain that. - There is just one case where s can be empty; if the input data contains no lines (i.e. if there is no input at all). In that case there are two behaviours possible; 1) no input => no output, or 2) always output something, if only 0. Both are sensible options depending on the application context. The +0 is addressing option 2). To address option 1) you'd rather have to write END {if(s) print s}. - Therefore it makes no sense to assume either option (for this corner case of no data) until it is specified by the question. Commented May 28, 2015 at 12:40
10
awk -F= '{sum+=$2};END{print sum}' 
9
  • 2
    We prefer long form answers. Can you please elaborate on how this works? Commented May 28, 2015 at 9:31
  • 2
    @slm, that answer is not any more or less verbose than the other answers here and is self explanatory. It also has the advantage of working with input like time=1.4e5sec Commented May 28, 2015 at 21:42
  • @StéphaneChazelas - agreed, but this is a new user and we do encourage users to provide more than single line answers. A bit of text explaining how it works would make it a much stronger answer than just code. Commented May 28, 2015 at 21:47
  • 4
    @slm, this is a new user with one of the best answers (from a technical stand point) and he gets two downvotes and a negative comment. Not a very warm welcome. Commented May 28, 2015 at 21:52
  • 1
    @TomFenech, the POSIX syntax for awk requires that those pattern/action items be separated by either ";" or "newline", so you may find awk implementations where it fails without this ";". Commented May 29, 2015 at 9:28
7

Another GNU awk one:

awk -v RS='[0-9]+' '{n+=RT};END{print n}' 

A perl one:

perl -lne'$n+=$_ for/\d+/g}{print$n' 

A POSIX one:

tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc 
6
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}' 
4
  • Awesome answer, but no need for sed: awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat Commented May 27, 2015 at 23:45
  • @user1717828: you should rather use the (shorter, and more compatible!) -F'=' instead of --field-separator = Commented May 29, 2015 at 9:14
  • @OlivierDulac, weird, my man awk only gives -F fs and --field-separator fs Commented May 29, 2015 at 10:40
  • @user1717828: -F'=' or -F '=' are 2 ways of doing the -F fs (fs is "=" in your case) . I added the singlequotes to ensure the fs is properly seen & interpreted by awk, not the shell (usefull if the fs is ';' for example) Commented May 29, 2015 at 11:56
4

You can try this:

awk -F"[^0-9]+" '{ sum += $2 } END { print sum+0; }' file 
4

Everyone has posted awesome awk answers, which I like very much.

A variation to @cuonglm replacing grep with sed:

sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc 
  1. The sed strips everything except for the numbers.
  2. The paste -sd+ - command joins all the lines together as a single line
  3. The bc evaluates the expression
3

You should use a calculator.

{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null 

With your four lines that prints:

time=31 time=223 time=241 time=784 

And more simply:

tr times=c ' + p' <infile |dc 

...which prints...

31 223 241 784 

If speed is what you're after then dc is what you want. Traditionally it was bc's compiler - and still is for many systems.

3
  • Not according to my measurements: it depends how much work you have to do to generate the formula Commented May 28, 2015 at 13:24
  • @glennjackman - your measurements don't include dc as near as I can tell. What are you talking about? Commented May 28, 2015 at 15:14
  • By the way, when comparing the old crew to the new crew - such as when you benchmark perl v the standard unix toolset - it really doesn't make much sense if you use GNU tools compiled on a GNU toolchain. All of the bloat that can negatively affect Perl's performance is also in all of those GNU-compiled GNU utils. Sad but true. You need a real, simply built, simple toolset to accurately judge the difference. Like an heirloom-toolchest set statically linked against musl libs for instance - in that way you can bench the one-tool/one-job paradigm vs the one-tool-to-rule-them-all one. Commented May 28, 2015 at 15:27
3

Through python3,

import re with open(file) as f: m = f.read() l = re.findall(r'\d+', m) print(sum(map(int, l))) 
3
  • re.findall returns a list of strings, this is not going to work Commented May 28, 2015 at 22:28
  • @1_CR ya , I forget that. Check it now. Commented May 29, 2015 at 4:10
  • Maybe sum(int(e) for e in l) is more pythonic. Commented May 29, 2015 at 15:18
3

Pure bash solution (Bash 3+):

while IFS= read -r line; do # While it reads a line: if [[ "$line" =~ [0-9]+ ]]; then # If the line contains numbers: ((counter+=BASH_REMATCH[0])) # Add the current number to counter fi # End if. done # End loop. echo "Total number: $counter" # Print the number. unset counter # Reset counter to 0. 

Short version:

while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0 
1
  • 1
    Maybe also: PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile Commented May 31, 2015 at 9:39

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.