Find total of marks for each student in the given file
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
Related videos on Youtube
Radhakrishnan Rk
Updated on September 18, 2022Comments
-
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 about 6 yearsI able to understand this. Thank you so much..! so getline within for loop will always fetch the next line?
-
Radhakrishnan Rk about 6 yearsThis 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 about 6 years@RadhakrishnanRk When the
awk
code reads the very first line of the file,name
will initially be empty, no output happens (sincename
is empty), butname
gets the value from$2
. When the secondName:
line is found, the collected data for the first person is printed, andname
is set to the name of the second person. In theEND
block, the collected data for the last person in the file is printed. -
Radhakrishnan Rk about 6 yearsYes. 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 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 aName:
line, the rest of the program is irrelevant for that particular line, so I usenext
to continue with the next line. -
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 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 about 6 yearsUnderstood 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 about 6 yearsSo 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 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 about 6 yearsThank you so much for showing patience in clarifying my doubts. :-)
-
Kusalananda about 6 years@RadhakrishnanRk Good! If this solves your issue, please consider accepting the answer.
-
gagiuntoli about 6 yearsyour welcome ! yes, every time
getline
is executeawk
goes to the next line.