0

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?

3
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
11
  • 1
    @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
    Feb 6 '18 at 7:44
  • 1
    @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
    Feb 6 '18 at 8:10
  • 1
    @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.
    – Kusalananda
    Feb 6 '18 at 9:04
  • 1
    @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.
    – Kusalananda
    Feb 6 '18 at 9:20
  • 1
    Thank you so much for showing patience in clarifying my doubts. :-) Feb 6 '18 at 9:23
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
2
  • I able to understand this. Thank you so much..! so getline within for loop will always fetch the next line? Feb 6 '18 at 6:49
  • 1
    your welcome ! yes, every time getline is execute awk goes to the next line.
    – gagiuntoli
    Feb 7 '18 at 13:52
0

Please find the below command to achieve the same

command:

 for i in Rad Din Hardy
> do
> sed -n "/$i/,+5p" p.txt| awk -F ":" '{print $2}'| sed "/$i/d"| awk -v i="$i" 'BEGIN{sum=0}{sum=sum+$1}END {print "Total marks of " i " "  sum}'
> done

output

Total marks of Rad 468
Total marks of Din 375
Total marks of Hardy 320

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.