6

How would you perform addition on the output of every line from awk?

For example

cat foo | awk '{print $1}
42
42
42

I'm looking for the answer to 42+42+42 (126).

I'm trying to write a for loop to do this, but there must be a simpler way

#Not Working, and way too complex
cat foo |awk  '{ print $1 }'|for i in $1 do; foo=$(( foo+$(i) )) done| echo $foo

I could pipe to wc -l but that only prints the number of lines, it does not evaluate them.

How can I evaluate each line from awk?

2
  • Do you need to do your addition after awk exits, or can you do the addition within awk? Sep 30 '13 at 20:42
  • Both doing the work inside awk or outside of awk would be acceptable.
    – spuder
    Sep 30 '13 at 20:47
11

A basic approach, using your example:

awk '{sum+=$1} END {print sum}' file
1
  • Note there is $ prefix to variables. Mar 15 '21 at 7:38
4

If you have control over the awk program, do the addition within awk as @jasonwryan shows.

If you really want to sum up the numbers that awk spits out, pipe the output into one of these:

| { tr '\n' '+' ; echo 0; } | bc
| { while read line; do ((sum+=line)); done; echo $sum; }

In the 2nd example, the echo command is within the grouping braces because bash runs the pipeline in a subshell, so changes to the $sum variable will not exist when the subshell exits.

2

Bash can't deal with decimals but it can handle simple manipulation of integers, you just need to use a trick like process substitution to make the variable accessible outside the loop:

n=0;while read i; do let n+=$i; done < <(awk '{print $1}' foo); echo $n;

or

n=0;while read i; do n=$((n+i)); done < <(awk '{print $1}' foo); echo $n;

The n=0 is there just to make sure that $n is always 0, otherwise, running these commands a second time would return 252 instead of 126.


While the most straightforward way would be to use gawk to make the calculation, you could also use a Perl one-liner:

awk '{print $1}' foo | perl -lne '$k+=$_;END{print "$k"};'

The -l flag removes newlines (chomp) and adds one to the end of each printed string, the -n means read the file line by line, saving each line as $_ and run the script provided with -e.

Or do the whole thing in Perl:

perl -alne '$k+=$F[0];END{print "$k"};' foo

The -a flag for Perl turns on automatic line splitting (like gawk). By default, fields are split on spaces but that can be changed using -F. The resulting fields are saved as the @F array so the 1st field is $F[0].

1
  • This is one reason I prefer ksh93 to bash - Korn actually supports floating-point math in the shell. ;)
    – dannysauer
    Oct 6 '13 at 20:11
1

The one-liner method i usually use for simple totals like this is to pipe to xargs to get all output from awk on one line, then through sed to transform spaces to pluses, and finally into bc to do the calculation:

cat foo | awk '{print $1} | xargs | sed -e 's/ /+/g' | bc
1
  • This is a nice alternate way of doing things Dec 6 '19 at 20:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.