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? Commented Sep 30, 2013 at 20:42
  • Both doing the work inside awk or outside of awk would be acceptable.
    – spuder
    Commented Sep 30, 2013 at 20:47

4 Answers 4

12

A basic approach, using your example:

awk '{sum+=$1} END {print sum}' file
1
  • Note there is $ prefix to variables. Commented Mar 15, 2021 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
    Commented Oct 6, 2013 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 Commented Dec 6, 2019 at 20:02

You must log in to answer this question.

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