Find total of marks for each student in the given file

19,398

Solution 1

You can search for Name and every time is found you go to the next numm lines and sum the scores:

#!/bin/bash
file=$1
num=$2
awk -v numm="$num" '
/Name/{
  mark = 0;
  printf("%s ",$2);
  for ( i=0; i<numm ; i++){
    getline;
    mark += $2;
  }
  printf("%d\n", mark);
}' $file

the result:

Rad 468
Din 375
Hardy 320

Solution 2

awk '/^Name:/ { if (name) printf("%s, score = %d\n", name, score); name = $2; score = 0; next }
              { score += $2 }
     END      { printf("%s, score = %d\n", name, score) }' file

Result:

Rad, score = 468
Din, score = 375
Hardy, score = 320

The first awk block is executed for each line that starts with the string Name:. If the name variable has a value, then the summed up score for the previous student is printed along with the student's name. Then the name is set to the second field of the current line and the score is reset to zero. The script then immediately continues with the next input line.

The second block is executed for every row of input that is not handled by the previous block. It simply adds the score to the value of the score variable.

The last block executes after reading the final line of the file and mimics the outputting done in the first block. This is so that the last student's result is outputted.


Duplicating code is ugly, so here's a solution that uses a function for doing the output:

awk 'function output() { if (name) printf("%s, score = %d\n", name, score) } 
     /^Name:/          { output(); name = $2; score = 0; next }
                       { score += $2 }
     END               { output() }' file

This was not part of the question, but might be interesting:

awk 'function output() { if (name) printf("%s\t score = %3d, mean = %.1f\n", name, score, score/count) } 
     /^Name:/          { output(); name = $2; score = count = 0; next }
                       { score += $2; ++count }
     END               { output() }' file

Output:

Rad      score = 468, mean = 93.6
Din      score = 375, mean = 75.0
Hardy    score = 320, mean = 64.0
Share:
19,398

Related videos on Youtube

Radhakrishnan Rk
Author by

Radhakrishnan Rk

Updated on September 18, 2022

Comments

  • Radhakrishnan Rk
    Radhakrishnan Rk over 1 year

    the file:

    Name: Rad
    Eng: 94
    Tam: 98
    Mat: 98
    Soc: 98
    Sci: 80
    Name: Din
    Eng: 87
    Tam: 89
    Mat: 78
    Soc: 87
    Sci: 34
    Name: Hardy
    Eng: 78
    Tam: 87
    Mat: 23
    Soc: 34
    Sci: 98
    

    the script :

    #!/bin/bash
    file=$1
    num=$2
    n=`wc -l < $file`
    it=$((n/num))
    echo $n
    echo $it
    awk -v numm="$num" '{if (NR<=numm){T+=$2}}END{print T}' $file
    

    My above script could generate total for first student. I want to find total for remaining two students marks also. Can someone help me with this?

  • Radhakrishnan Rk
    Radhakrishnan Rk about 6 years
    I able to understand this. Thank you so much..! so getline within for loop will always fetch the next line?
  • Radhakrishnan Rk
    Radhakrishnan Rk about 6 years
    This is little bit confusing for me. Will the first name be stored in the variable 'name' before assigning name=$2. Does the result are printed from END block are from IF block? Can you please help me to understand better. I am not able to get what you explained. this command looks difficult for me to understand. Reagrds, Radhakrishnan
  • Kusalananda
    Kusalananda about 6 years
    @RadhakrishnanRk When the awk code reads the very first line of the file, name will initially be empty, no output happens (since name is empty), but name gets the value from $2. When the second Name: line is found, the collected data for the first person is printed, and name is set to the name of the second person. In the END block, the collected data for the last person in the file is printed.
  • Radhakrishnan Rk
    Radhakrishnan Rk about 6 years
    Yes. I am getting that name is empty. But I could not get how previous person score is printed? I have following doubts too.. what 'next' performs? 'score +=$2' executed till next occurrence of Name? So printf from IF block printed how many output? and printf from END block printed how many lines?
  • Kusalananda
    Kusalananda about 6 years
    @RadhakrishnanRk The next command will make the program immediately jump to the beginning of the script and read the next line from the input data. If we have found a Name: line, the rest of the program is irrelevant for that particular line, so I use next to continue with the next line.
  • Kusalananda
    Kusalananda about 6 years
    @RadhakrishnanRk The END block will print at most one line of output (that for the last student). The rest of the output happens in the earlier block.
  • Kusalananda
    Kusalananda about 6 years
    @RadhakrishnanRk Yes, every block is applied to the current input line if it matches the corresponding pattern. If the next command is executed, however, the script continues from the beginning with the next input line.
  • Radhakrishnan Rk
    Radhakrishnan Rk about 6 years
    Understood with END block printf. But 'next' command utility is not understandable. May be I am missing the logic behind curly braces {}. Why 'if (name) printf("%s, score = %d\n", name, score:)'and 'name = $2;' and 'score = 0;' and 'next' are enclosed in same curly braces when ' score += $2' is enclosed in an another curly braces?
  • Radhakrishnan Rk
    Radhakrishnan Rk about 6 years
    So i) printf("%s, score = %d\n", name, score) ii)name = $2;iii) score = 0; iv) next -- all these four will be executed only when /Name/ occurs ? And remaining line score +=$2 executes for all input lines except those lines matching /Name/. Am I in right way? This exception is done using 'next'
  • Kusalananda
    Kusalananda about 6 years
    @RadhakrishnanRk You are entirely correct (in that last comment). Awk scripts are built using patterns and actions. An action is what's in a {...} block. An action without a pattern will be executed for every line.
  • Radhakrishnan Rk
    Radhakrishnan Rk about 6 years
    Thank you so much for showing patience in clarifying my doubts. :-)
  • Kusalananda
    Kusalananda about 6 years
    @RadhakrishnanRk Good! If this solves your issue, please consider accepting the answer.
  • gagiuntoli
    gagiuntoli about 6 years
    your welcome ! yes, every time getline is execute awk goes to the next line.