2

I have an array trf. Would like to compute the sum of the second element in each array entry.

Example of array contents

trf=( "2 13 144" "3 21 256" "5 34 389" )

Here is the current implementation, but I do not find it robust enough. For instance, it fails with arbitrary number of elements (but considered constant from one array element to another) in each array entry.

   cnt=0
   m=${#trf[@]}
   while (( cnt < m )); do
     while read -r one two three
     do
       sum+="$two"+
     done <<< $(echo ${array[$count]})
     let count=$count+1
   done

   sum+=0
   result=`echo "$sum" | /usr/bin/bc -l`
1
  • Please add your desired output (no description, no images, no links) for that sample input to your question (no comment). Commented Sep 6, 2021 at 19:01

4 Answers 4

3

You're making it way too complicated. Something like

#!/usr/bin/env bash
trf=( "2 13 144" "3 21 256" "5 34 389" )
declare -i sum=0 # Integer attribute; arithmetic evaluation happens when assigned
for (( n = 0; n < ${#trf[@]}; n++)); do
    read -r _ val _ <<<"${trf[n]}"
    sum+=$val
done
printf "%d\n" "$sum"

in pure bash, or just use awk (This is handy if you have floating point numbers in your real data):

printf "%s\n" "${trf[@]}" | awk '{ sum += $2 } END { print sum }'
Sign up to request clarification or add additional context in comments.

4 Comments

Or if you can install GNU datamash, printf "%s\n" "${trf[@]}" | datamash -W sum 2
I like the capability for floating point computations.
How could I modify the awk command so that the field number is taken from an outside variable?
@Angio awk -v f=2 '{ sum += $f } END { print sum }'
2

You can use printf to print the entire array, one entry per line. On such an input, one loop (while read) would be sufficient. You can even skip the loop entirely using cut and tr to build the bc command. The echo 0 is there so that bc can handle empty arrays and the trailing + inserted by tr.

{ printf %s\\n "${trf[@]}" | cut -d' ' -f2 | tr \\n +; echo 0; } | bc -l

For your examples this generates prints 68 (= 13+21+34+0).

Comments

2

Try this printf + awk combo:

$ printf '%s\n' "${trf[@]}" | awk '{print $2}{a+=$2}END{print "sum:", a}'
13
21
34
sum: 68

Oh, it's already suggested by Shawn. Then with loop:

$ for item in "${trf[@]}"; do
    echo $item
done | awk '{print $2}{a+=$2}END{print "sum:", a}'
13
21
34
sum: 68

Comments

2

For relatively small arrays a for/while double loop should be ok re: performance; placing the final sum in the $result variable (as in OP's code):

result=0

for element in "${trf[@]}"
do
    read -r a b c <<< "${element}"
    ((result+=b))
done

echo "${result}"

This generates:

68

For larger data sets I'd probably opt for one of the awk-only solutions (for performance reasons).

1 Comment

Why you need while loop ? This could be done with read -r a b c <<< "${element}"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.