Tree55Topz
Tree55Topz

Reputation: 1142

Finding averages from reading a file using Bash Scripting

I am trying to write a bash script that reads a file 'names.txt' and will compute the average of peoples grades. For instance, names.txt looks something like this.

900706845 Harry Thompson 70 80 90
900897665 Roy Ludson 90 90 90 

The script should read the line, print out the ID# of the person, the average of the three test scores and the corresponding letter grade. So the output needs to look like this

900706845 80 B
900897665 90 A

Heres what I have

    #!/bin/bash
    cat names.txt | while read x
    do 
         $SUM=0; for i in 'names.txt'; do SUM=$(($SUM + $i));
         done;

         echo $SUM/3
    done

I understand the echo will only print out the averages at this point, but I am trying to atleast get it to compute the averages before I attempt the other parts as well. Baby steps!

Upvotes: 2

Views: 3614

Answers (4)

John1024
John1024

Reputation: 113994

The ID#s and averages can be obtained as follows:

$ awk '{sum=0; for(i=3;i<=NF;i++) sum+=$i ; print $1, sum/3}' names.txt 
900706845 80
900897665 90

Guessing at how to compute grades, one can do:

$ awk '{sum=0; for(i=3;i<=NF;i++) sum+=$i ; ave=sum/3; print $1, ave, substr("FFFFFDCBA", ave/10, 1) }' names.txt 
900706845 80 B
900897665 90 A

The above solutions work for any number of tests but names are limited to 2 words. If there will always be three tests but names can be any number of words, then use:

$ awk '{ave=($(NF-2)+$(NF-1)+$NF)/3; print $1, ave, substr("FFFFFDCBA", ave/10, 1) }' names.txt
900706845 80 B
900897665 90 A

Upvotes: 0

user1461760
user1461760

Reputation:

With a awk one-liner:

awk '{ AVG = int( ( $(NF-2) + $(NF-1) + $(NF) ) / 3 ) ; if ( AVG >= 90 ) { GRADE = "A" } else if ( AVG >= 80 ) { GRADE = "B" } else if ( AVG >= 70 ) { GRADE = "C" } else if ( AVG >= 60 ) { GRADE = "D" } else { GRADE = "F" } ; print $1, AVG, GRADE }' file

Let's look at the details:

awk '{

  # Calculate average
  AVG = int( ( $(NF-2) + $(NF-1) + $(NF) ) / 3 )

  # Calculate grade
  if ( AVG >= 90 ) { GRADE = "A" }
  else if ( AVG >= 80 ) { GRADE = "B" }
  else if ( AVG >= 70 ) { GRADE = "C" }
  else if ( AVG >= 60 ) { GRADE = "D" }
  else { GRADE = "F" }

  print $1, AVG, GRADE

}' file

Upvotes: 0

mike.dld
mike.dld

Reputation: 3049

Customize gradeLetter for your own needs:

#!/bin/sh

awk '
  function gradeLetter(g)
  {
    if (g >= 90) return "A";
    if (g >= 80) return "B";
    if (g >= 70) return "C";
    if (g >= 60) return "D";
    return "E"
  }
  {
    avgGrade = ($(NF) + $(NF - 1) + $(NF - 2)) / 3;
    print $1, avgGrade, gradeLetter(avgGrade)
  }' names.txt

Upvotes: 0

Mark Setchell
Mark Setchell

Reputation: 208107

Like this maybe:

#!/bin/bash
while read a name1 name2 g1 g2 g3
do
   avg=$(echo "($g1+$g2+$g3)/3" | bc)
   echo $a $name1 $name2 $avg
done < names.txt

Output:

900706845 Harry Thompson 80
900897665 Roy Ludson 90

Upvotes: 2

Related Questions