how to do decimal arithmetic in shell script

hi,

I have a file with decimal/non-decimal values

$ cat b22
373 164 92 62 20 131 94 12 129 111 95 154 37 15 447 25 7.4 135 77 122 32 92 70 57 37 42 72 17 13 97 40 41 53 22 80 71 29 87 23 31 273 6.2 12K 43 44 45 22 11 7.7 13 18 173 36 20 18 13 56 67 104 53 5.4 241 19 13 3.8 38 14 31 329 16 155 17 81 74 18 45 110 58 23 4.0 13 33 6.9 32 68 28 22 34 139 60 31 22 101 12 13 105 14 19 109 11 6.6 65 44 9.0 132 221 16 16 166 11 76 46 38 42 18 87 68 29 5.4 3.4 41 32 27 406 275 35 24 26 49 5.2 19 146 60 41 12 7.9 77 14 15 24 29 98 24 98 187 56 96 9.5 46 60 24 25 169 196 13 37 16 50 76 12 181 12 74 8.2 26 112 21 12 86 41 1.5 2.3 130 8.2 415 36 24 18 52 54 17 11 8.1 9.2 101 15 85 44 43 107 21 19 111 6.2 26 42 15 39 116 33 49 60 20 127 7.6 55 84 87 34 32 22 21 66 102 29 14 20 7.7 27 22 12 25 138 45 6.4 40 18 34 103 22 18 64 106 121 7.7 16 75 9.3 7.9 23 4.8 28 40 63 23 50 3.4 14 1.5 24 5.4 9.2 16 73 34 150 13 41 120 127 260 4.3 147 14 29

I am trying to add these values
however, expr and let would fail

 
expr: non-numeric argument
 
-bash: let: a=1.2+2.8: syntax error: invalid arithmetic operator

I am trying to add these with this code

 
$ $sum=0; for i in `cat b22`
> do
> sum=`echo "$sum + $i" | bc`
> done; echo $sum;

but it throws the following error 256 times [same asthe no. of values in file b22]

(standard_in) 1: parse error
 awk 'BEGIN { print ( 1.2 + 1.25 ) }'
2.45

please provide a reply specific to the problem scenario depicted

awk '
BEGIN {FS=OFS=" "}
{
sum=0; n=0
for(i=1;i<=NF;i++)
     {sum+=$i; ++n}
     print "sum:"sum
}' temp_test
$sum=0; for i in `cat b22`
do
sum=`echo "$sum + $i" | bc`
done; echo $sum;

would have worked if you had changed $sum=0 on the first line to sum=0
I assume that the variable sum was not set when you started so the first command turned into =0 when $sum expanded to an empty string.

However, it is pretty inefficient to invoke bc for each value you want to add. A much simpler way would be to use:

awk ' {	for (i=1; i<= NF; i++) sum+=$i }
END {print sum}' b22

which only invokes awk once instead of invoking bc 265 times. (Note that you have 265 values in b22; not 256.)

1 Like

If b22 is properly formatted (right now there is a 12K in there; how to interpret?) this is reasonably fast:

tr ' ' '+' <b22|bc

For a pure shell solution, you can use ksh (precisely ksh93) which supports fractional arithmetic natively:

sum=0
for i in $(<b22); do
    sum=$((sum + i))
done
echo $sum

I hate to argue with my own suggestions, but I didn't actually try looping through calls to bc when I saw the obvious typo. The rest of the shell script looked OK. What I didn't notice was that your input file has one entry that is "12K", so the bc adding the sum calculated from the previous values in the input + 12K fails and the remaining calls to bc also fail. It wasn't noticed when running the awk script because awk ignore non-numeric trailing characters with performing arithmetic operations on variables contain string values that start with decimal digit string (including an optional <period>).

So you need to fix your input to get correct results if you use any of the suggestions using bc. (And if "12K" wasn't supposed to be "12", you get the wrong result from awk as well.)

Assuming the list only contains numbers (not the '12K' currently there which you haven't said how to interpret) you could do it in ksh93 like this:

set $(<b22)
s=0
for i; do ((s += $i)); done
echo $s