我正在编写一个 Bash 脚本来计算学生的 GPA,同时考虑到可能重复的课程。我的目标是确保如果学生重修课程,则 GPA 计算中仅考虑最新成绩。此外,我想排除没有成绩的科目,因为这些科目代表当前正在进行的课程。
我使用的是 Bash 版本 5,因此我可以使用关联数组,并且我尝试利用它们来跟踪每门课程的最新尝试。
但是,我的脚本没有按预期运行——它考虑了重复课程的两次尝试,而不仅仅是最新的一次。以下是我的脚本的相关部分:
#!/bin/bash
# Define a function to convert grades to points
grade_to_points() {
case $1 in
A) echo 4 ;;
A-) echo 3.7 ;;
B+) echo 3.3 ;;
B) echo 3 ;;
B-) echo 2.7 ;;
C+) echo 2.3 ;;
C) echo 2 ;;
D) echo 1 ;;
F) echo 0 ;;
*) echo -1 ;; # for subjects with no grade
esac
}
# Extract the list of subject files and student IDs
subject_files=()
student_ids=()
read_subjects=true
for arg in "$@"; do
if [[ $arg == "student" ]]; then
read_subjects=false
continue
fi
if $read_subjects; then
subject_files+=($arg)
else
student_ids+=($arg)
fi
done
# Loop through each student ID to generate the transcript
for student_id in "${student_ids[@]}"; do
# Get the student's name from student.dat
student_name=$(grep "^$student_id" student.dat | cut -d ' ' -f 2-)
echo "Transcript for $student_id $student_name"
total_points=0
subjects_count=0
# Loop through each subject file to find grades for the student
for subject_file in "${subject_files[@]}"; do
if grep -q "^$student_id" $subject_file; then
# Extract subject details and grade
subject_code=$(head -n 1 $subject_file | cut -d ' ' -f 2)
academic_year=$(head -n 1 $subject_file | cut -d ' ' -f 3)
semester=$(head -n 1 $subject_file | cut -d ' ' -f 4)
grade=$(grep "^$student_id" $subject_file | awk '{print ($2=="") ? "" : $2}')
# Print subject details
echo "$subject_code $academic_year Sem $semester $grade"
# Calculate GPA if grade is present
if [[ $grade != "" ]]; then
points=$(grade_to_points $grade)
if [[ $points != -1 ]]; then
total_points=$(echo "$total_points + $points" | bc)
((subjects_count++))
fi
fi
fi
done
# Calculate and print GPA if there are graded subjects
if [[ $subjects_count -gt 0 ]]; then
gpa=$(echo "scale=2; $total_points / $subjects_count" | bc)
echo "GPA for $subjects_count subjects $gpa"
else
echo "No graded subjects found."
fi
echo # New line for separation
done
我得到的输入输出错误:
transcript COMP* student 1236 1234 1223
Transcript for 1236 peter
COMP1011 2021 Sem 2 A
COMP2411 2022 Sem 1 A
COMP2432 2022 Sem 2
GPA for 2 subjects 4.00
Transcript for 1234 john
COMP1011 2021 Sem 2 B
COMP2411 2022 Sem 1 B-
GPA for 2 subjects 2.85
Transcript for 1223 bob
COMP1011 2021 Sem 2 F
COMP1011 2022 Sem 1 B
COMP2411 2022 Sem 1 C+
COMP2432 2022 Sem 2
GPA for 3 subjects 1.76
我应该得到输入的正确输出:
transcript COMP* student 1236 1234 1223
Transcript for 1236 peter
COMP1011 2021 Sem 2 A
COMP2411 2022 Sem 1 A
COMP2432 2022 Sem 2
GPA for 2 subjects 4.00
Transcript for 1234 john
COMP1011 2021 Sem 2 B
COMP2411 2022 Sem 1 B
GPA for 2 subjects 2.85
Transcript for 1223 bob
COMP1011 2021 Sem 2 F
COMP1011 2022 Sem 1 B
COMP2411 2022 Sem 1 C+
COMP2432 2022 Sem 2
GPA for 2 subjects 2.65
我使用的文件和内容:
student.dat
1223 bob
1224 kevin
1225 stuart
1226 otto
1234 john
1235 mary
1236 peter
1237 david
1238 alice
COMP101121S2.dat
Subject COMP1011 2021 2
1223 F
1234 B
1235 B+
1236 A
COMP101122S1.dat
Subject COMP1011 2022 1
1223 B
1224 B+
1225 B1238 C+
COMP241122S1.dat
Subject COMP2411 2022 1
1223 C+
1234 B1235 B
1236 A
COMP243222S2.dat
Subject COMP2432 2022 2
1223
1235
1236
1237
这是我尝试过的:
使用关联数组来跟踪每门课程的最新尝试。不幸的是,这似乎没有按预期工作。
确保我的 Bash 版本支持关联数组,自从我使用版本 5 以来它就支持关联数组。
我的要求是:
如果学生未及格并重修同一科目,则在 GPA 计算中仅考虑最新成绩。
如果存在重考,则忽略不及格成绩,但如果没有重考,则将其包括在内。
不要计算没有成绩的科目,因为它们代表正在进行的课程。
任何人都可以建议如何修改我的脚本以满足这些要求吗?任何帮助将不胜感激!
以下是如何使用 awk 执行此操作的起点:
$ cat tst.sh
#!/usr/bin/env bash
awk '
function grade_to_points(grade, grade2pts,dfltPts) {
grade2pts["A"] = 4
grade2pts["A-"] = 3.7
grade2pts["B+"] = 3.3
grade2pts["B"] = 3
grade2pts["B-"] = 2.7
grade2pts["C+"] = 2.3
grade2pts["C"] = 2
grade2pts["D"] = 1
grade2pts["F"] = 0
dfltPts = -1 # for subjects with no grade
return ( grade in grade2pts ? grade2pts[grade] : dfltPts )
}
NR == FNR {
studId = $1
studName = gensub(/^\S+\s+/,"",1)
studId2Name[studId] = studName
next
}
FNR == 1 {
courseSubj = $2
courseYear = $3
courseSem = $4
next
}
{
studId = $1
grade = $2
studIdCourseSubjYearSem2Grade[studId][courseSubj][courseYear][courseSem] = grade
}
END {
PROCINFO["sorted_in"] = "@ind_str_asc"
for ( id in studIdCourseSubjYearSem2Grade ) {
totPoints = totSubjs = 0
print "Transcript for", id, studId2Name[id]
for ( subj in studIdCourseSubjYearSem2Grade[id] ) {
totSubjs ++
for ( year in studIdCourseSubjYearSem2Grade[id][subj] ) {
for ( sem in studIdCourseSubjYearSem2Grade[id][subj][year] ) {
grade = studIdCourseSubjYearSem2Grade[id][subj][year][sem]
totPoints += grade_to_points(grade)
print subj, year, "Sem", sem, grade
}
}
}
printf "GPA for %d subjects %0.2f\n\n", totSubjs, (totSubjs ? totPoints / totSubjs : 0)
}
}
' student.dat COMP101121S2.dat COMP101122S1.dat COMP241122S1.dat COMP243222S2.dat
$ ./tst.sh
Transcript for 1223 bob
COMP1011 2021 Sem 2 F
COMP1011 2022 Sem 1 B
COMP2411 2022 Sem 1 C+
COMP2432 2022 Sem 2
GPA for 3 subjects 1.43
Transcript for 1224 kevin
COMP1011 2022 Sem 1 B+
GPA for 1 subjects 3.30
Transcript for 1225 stuart
COMP1011 2022 Sem 1 B
GPA for 1 subjects 3.00
Transcript for 1234 john
COMP1011 2021 Sem 2 B
COMP2411 2022 Sem 1 B
GPA for 2 subjects 3.00
Transcript for 1235 mary
COMP1011 2021 Sem 2 B+
COMP2411 2022 Sem 1 B
COMP2432 2022 Sem 2
GPA for 3 subjects 1.77
Transcript for 1236 peter
COMP1011 2021 Sem 2 A
COMP2411 2022 Sem 1 A
COMP2432 2022 Sem 2
GPA for 3 subjects 2.33
Transcript for 1237 david
COMP2432 2022 Sem 2
GPA for 1 subjects -1.00
Transcript for 1238 alice
COMP1011 2022 Sem 1 C+
GPA for 1 subjects 2.30
如果重考,它不会执行您想要的忽略不及格成绩的操作,但希望您会发现上述内容比现有的 bash 脚本更容易理解和修改以执行您想做的任何操作。