39

I run the following command:

grep -o "[0-9] errors" verification_report_3.txt | awk '{print $1}'

and I get the following result:

1
4
0
8

I'd like to add each of the numbers up to a running count variable. Is there a magic one liner someone can help me build?

5 Answers 5

55
grep -o "[0-9] errors" verification_report_3.txt | awk '{ SUM += $1} END { print SUM }'

That doesn't print the list but does print the sum. If you want both the list and the sum, you can do:

grep -o "[0-9] errors" verification_report_3.txt | awk '{ SUM += $1; print $1} END { print SUM }'
8
  • Shawn - thank you for your answer. How do I return total back to the bash script out of awk? Dec 14, 2010 at 21:28
  • 2
    @Amir You would use the first one like this variable=$(grep -o "[0-9] errors" verification_report_3.txt | awk '{ SUM += $1} END { print SUM }') This puts the output of the command (which is only the sum value) into the variable called variable Dec 14, 2010 at 21:33
  • 4
    @Amir Afghani Also, you might want to change your grep to "[0-9]\+ errors". This will match if you have a line reporting >9 errors. Dec 14, 2010 at 21:36
  • Yup, wow I can't believe I missed that. Thank you. Dec 14, 2010 at 21:43
  • Shawn, the output seems like it's not adding up my results. It looks like this: Total Errors = +259+7581+8852+2014+3189++13572+11438+++6+4172+ Dec 14, 2010 at 21:58
13

This can all be done in awk as well:

awk '"[0-9]+ errors" {sum += $1}; END {print sum}' verification_report_3.txt
6

You appear to be using GNU system, so if Perl regular expressions support is available, you could write something like this:

grep -Po '[0-9]+(?=\s+errors)' infile | 
  paste -sd+ | 
    bc

P.S. I modified the regular expression (added the + quantifier) to allow numbers > 9.

P.S. Alternatively, awk is sufficient (assuming GNU awk):

awk 'END { print s }
/[0-9]+[[:space:]]+errors/ { 
  s += $1 
  }' infile
1
  • the first one for me just prints what already went into the pipe...
    – xeruf
    May 3, 2018 at 19:46
4

I use this:

$ echo $(cat file | sed 's/$/+/') 0 | bc

It isn't efficient for large lists, but for most of my use cases it is fine. I usually use a shell function to automate the process so that I only have to provide a file name:

## cheezy summation
##   call from .bashrc
##
getsum () { echo $(cat $1 | sed 's/$/+/') 0 | bc; }
gethsum () { echo $(cat $1 | sed 's/[gG]/*1000M/' | sed 's/[mM]/*1000K/' | sed 's/[kK]/*1000/' | sed 's/$/+/') 0 | bc; }
gethexsum () { echo ibase=16 $(cat $1 | sed 's/$/+/') 0 | bc; }

You can always substitute the end-of-line marker for a specific element separator or character class if your data is delimited in another fashion.

3

Try piping the output from your grep into

awk 'BEGIN {total=0;}{total+=$1;}END {print "Total: ",total}'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .