Reputation: 1142
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
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
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
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
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