user2935569
user2935569

Reputation: 347

sum up a column in text file - bash

the text file

student.txt

jane,good,3
bob,bad,2.6
annie,good,2.8
dan,bad,2

first I tried to print all the good student which is successful

#!/bin/bash

while IFS=, read -r -a array; do
   [[  "${array[1]}" == "good"  ]] || continue
   printf "%s \n" "${array[0]}" is a ${array[1]} student"
   done  <  "student.txt"

output

jane is a good student
annie is a good student

next I also want to sum up all the numbers of the third column in the text file after printing the types of student and it was not successful

#!/bin/bash
while IFS=, read -r -a array; do
   [[  "${array[1]}" == "good"  ]] || continue
   printf "%s \n" "${array[0]}" is a ${array[1]} student"

   for n in "${array[2]}"; do
      total=$( "$total +=$n" | bc )
      echo $total
   done
done  <  "student.txt"

output

jane is a good student
+=3: command not found
annie is a good student
+=2.8: command not found

expected output

jane is a good student
annie is a good student
total = 5.8

As I am new to bash scripting , I need to seek help from you guys.

Oh another thing, I can't seem to make good use of awk utility.

even if I tried a simple statement using awk
e.g

awk -F","  "{print $1}"  "student.txt"

by right if I am not wrong it should return something like this

output

good
bad
good
bad

but instead it returns me the whole value of the textfile which I have no idea why

my output for awk -F"," "{print $1}" "student.txt"

jane,good,3
bob,bad,2.6
annie,good,2.8
dan,bad,2

so I guess any suggestion use awk method is out.

Upvotes: 1

Views: 760

Answers (3)

Fritz G. Mehner
Fritz G. Mehner

Reputation: 17188

Pure Bash. The missing floating point arithmetic is emulated.

total=0
while IFS=, read -r -a array
do
  [[  "${array[1]}" == "good"  ]] || continue
  printf "%s \n" "${array[0]} is a ${array[1]} student"

  [[ "${array[2]}" =~ ([0-9])(\.([0-9]))? ]]
  (( total += 10*${BASH_REMATCH[1]} + ${BASH_REMATCH[3]:-0} ))
done  <  "student.txt"

printf "total = %d.%d" $((total/10)) $((total%10)

output

jane is a good student 
annie is a good student 
total = 5.8

Upvotes: 0

gniourf_gniourf
gniourf_gniourf

Reputation: 46823

This should do (no awk):

#!/bin/bash
total=0
while IFS=, read -r -a array; do
    [[  "${array[1]}" == "good"  ]] || continue
    printf "%s is a %s student\n" "${array[@]:0:2}"
    total=$(bc <<< "$total+${array[2]}")
done < "student.txt"
echo "$total"

Now this forks on bc for each student. Instead, you could abuse IFS as so:

#!/bin/bash
total=()
while IFS=, read -r -a array; do
    [[  "${array[1]}" == "good"  ]] || continue
    printf "%s is a %s student\n" "${array[@]:0:2}"
    total+=( "${array[2]}" )
done < "student.txt"
# Abusing IFS, I know what I'm doing!
IFS="+" bc <<< "${total[*]}"

:)

Or, without IFS abuse and not saving data in memory in an array:

#!/bin/bash
{
    while IFS=, read -r -a array; do
        [[  "${array[1]}" == "good"  ]] || continue
        printf >&2 "%s is a %s student\n" "${array[@]:0:2}"
        printf "%s+" "${array[2]}"
    done < "student.txt"
    echo "0"
} | bc

Remark. In the last case, we have to artificially add a 0.

Exercise. Use dc instead of bc.

Upvotes: 0

Kent
Kent

Reputation: 195059

try this one-liner:

awk -F, '$2=="good"{print $1" is good";s+=$3}END{print "total:"s}' file

outputs:

jane is good
annie is good
total:5.8

Upvotes: 4

Related Questions