Search code examples
bashsortingpiping

How do I combine a bash script that sorts, calculates an average, and prints?


We can't use awk or make a new file to store data.

My brain can't solve this problem. We are given a data set like this:

299226663 Laney Camp 70 74 71 
434401929 Skyler Camp 78 81 82 
199144454 Tracey Camp 77 84 84 

We have to calculate the average, and print results like this:

71 [299226663] Camp, Laney  
80 [434401929] Camp, Skyler 
81 [199144454] Camp, Tracey

I have separate pieces of bash code that all work, but I can't figure out how to combine them.

This sorts the correct way

sort -t' ' -k3,3 -k2,2 -k1,1n StudentGrades.txt

And this next part is definitely wrong and I expect it to get torn apart, but it does compute the averages and print the correct format, except it skips the last line of StudentGrades.txt for some reason:

filename='StudentGrades.txt'

while read LINE
do 
var1=$(echo $LINE | cut -d' ' -f1)
var2=$(echo $LINE | cut -d' ' -f2)
var3=$(echo $LINE | cut -d' ' -f3)
var4=$(echo $LINE | cut -d' ' -f4)
var5=$(echo $LINE | cut -d' ' -f5)
var6=$(echo $LINE | cut -d' ' -f6)

let a=(var4+var5+var6)/3
echo $a [$var1] $var3, $var2 


done < StudentGrades.txt

I can't figure out a way to get the average, and format, and sort without moving the second script to a new file and calling a sort command on it. Any ideas? It'll probably take bigger changes because I have no faith in that second part lol.


Solution

  • Regarding the missing last line issue, it is a common pitfall of read command because it returns false if the line does not contain a newline code at the end of the line, which often occurs with the last line depending on a text editor.
    As a workaround, try while read LINE || [ -n "${LINE}" ] instead of while read LINE.
    In addition to that, consider to say set -- $LINE instead of splitting with cut command respectively. It automatically assigns each columns into positioal parameters $1, $2, and so on. Then your script will work much faster. BTW your average calculation truncates the fractional part without rounding it to the nearest integer. Is that okay?

    Summarizing above, I would modify your script as follows:

    #!/bin/bash
    
    sort -t' ' -k3,3 -k2,2 -k1,1n StudentGrades.txt | while read LINE || [ -n "${LINE}" ]; do
        set -- $LINE
    
        let a=($4*10 + $5*10 +$6*10 + 15)/30
        # If you want to preserve the 1st decimal place, replace the line above with:
        # a=$( echo $(( ($4*10 + $5*10 +$6*10 ) / 3 )) | sed -e "s/\(.\)$/.\1/" )
    
        echo $a [$1] $3, $2
    
    done