← 项目列表
课程已完成2026年6月

Linux 成绩管理系统(Shell)

纯 Shell 脚本实现的成绩管理系统,多用户数据隔离、灵活查询、完善注释。

ShellLinux成绩管理ShellBashawksed
📋 项目概览
技术栈
ShellBashawksed
功能特性
  • 多用户登录(教师/学生)
  • 成绩增删改查 + 模糊搜索
  • CSV 批量导入成绩
  • 统计计算(平均分/最高低分/及格率)
  • 文本文件持久化 + 数据导出
📖 技术分析报告在 GitHub 查看 ↗

Shell 成绩管理系统

与本课程完整项目的关系:本目录是 Shell 脚本实现的成绩管理系统(作业五)。该系统的 Flask Web 迁移版(作业六)在相同权限模型和数据逻辑基础上,将 CLI 交互替换为浏览器界面,并使用 SQLite 替代 CSV 文件存储。

项目概述

基于 Bash 的全功能成绩管理系统,实现学生成绩的增删改查、排序统计、三级权限控制和多维度报表导出。数据存储于 CSV 文件,通过 Shell 脚本完成所有操作,是一次将 Shell 编程能力推向工程化边界的尝试。

架构设计

系统采用函数式模块化设计,主流程为:数据初始化 -> 班级配置加载 -> 用户认证 -> 主菜单循环。核心数据流通过 get_data_lines() 函数实现用户数据隔离,admin 看到全部数据,teacher 看到管辖班级,student 看到本人记录。

功能模块分为四个层级:基础 CRUD(添加/删除/修改/查询学生)、排序(按科目/总分/平均分)、统计报表(分布/平均分/GPA/挂科名单)、加分模块(班级维度统计/学院汇总/用户管理/报表导出)。每个子功能对应独立的函数,通过子菜单组织调用。

技术亮点

三级权限与数据隔离:用户系统支持 admin/teacher/student 三种角色,通过 SESSION_ROLE 和 SESSION_SCOPE 变量控制数据可见性和操作权限。teacher 只能操作管辖班级的学生,student 只能查询自己,admin 拥有全部权限。get_data_lines() 函数根据角色动态过滤数据行。

纯 Shell 的数值计算方案:由于 Bash 不支持浮点运算,系统封装了 awk_add/awk_mul/awk_div 等工具函数,所有数值计算委托给 awk 完成。grade_to_num() 函数将优秀/良好/中等/及格/不及格等中文等级映射为数值分数,支持混合评分体系。

批量录入功能:支持一次输入多行"学号 成绩"数据批量写入 CSV,学号支持短号自动补全(后 4 位自动加前缀 20181828),教师视角自动验证管辖班级权限。这是期末登分场景下最实用的功能。

设计决策

选择 CSV 文件存储而非数据库,因为作业要求纯 Shell 实现,且 CSV 的文本格式便于 sed/awk 直接操作。class_info.txt 作为班级-学院-系的映射配置文件,比硬编码更灵活。报表导出到独立的 report/ 目录,每次导出带时间戳防止覆盖。

关键代码解读

get_data_lines() {
    case "$SESSION_ROLE" in
        admin)    echo "$all_data" ;;
        teacher)  # 只返回管辖班级的学生行 ;;
        student)  grep "^$SESSION_SCOPE," ;;
    esac
}

该函数是整个权限系统的枢纽。所有查询、排序、统计操作都通过 get_data_lines 获取数据,而非直接读取 CSV 文件,确保数据隔离在源头实现而非分散在各函数中。这种"一次过滤、多处使用"的设计在 Shell 脚本中尤为简洁高效。

🚀 在线演示新窗口打开 ↗
💻 核心代码Shell · Bash · awk · sed
bash主程序框架grade_manager.sh · 132 行

Shell 脚本主循环,包括用户认证、菜单导航、成绩管理和统计功能。

#!/bin/bash
# =============================================
# Linux 课程作业五 — 成绩管理系统
# 作者: 童国睿
# 功能: 多用户成绩管理(增删改查+统计)
# =============================================

DATA_DIR="./data"
USERS_FILE="$DATA_DIR/users.txt"
GRADES_FILE="$DATA_DIR/grades.txt"

# ── 初始化 ──
init() {
    mkdir -p "$DATA_DIR"
    [ -f "$USERS_FILE" ] || echo "admin|admin123|teacher" > "$USERS_FILE"
    [ -f "$GRADES_FILE" ] || touch "$GRADES_FILE"
}

# ── 登录 ──
login() {
    read -p "用户名: " username
    read -s -p "密码: " password
    echo
    user=$(grep "^$username|$password|" "$USERS_FILE")
    if [ -z "$user" ]; then
        echo "❌ 用户名或密码错误"
        return 1
    fi
    role=$(echo "$user" | cut -d'|' -f3)
    echo "✅ 登录成功![$role] $username"
    ROLE="$role"
    USERNAME="$username"
}

# ── 显示所有成绩 ──
list_grades() {
    printf "%-12s %-15s %-10s %-6s\n" "学号" "姓名" "课程" "成绩"
    printf "%-12s %-15s %-10s %-6s\n" "────" "────" "────" "────"
    while IFS='|' read -r sid name course score; do
        [ -n "$sid" ] && printf "%-12s %-15s %-10s %-6s\n" "$sid" "$name" "$course" "$score"
    done < "$GRADES_FILE"
    echo ""
    echo "总记录数: $(wc -l < "$GRADES_FILE")"
}

# ── 添加成绩 ──
add_grade() {
    read -p "学号: " sid
    read -p "姓名: " name
    read -p "课程: " course
    read -p "成绩: " score
    # 校验成绩范围
    if ! [[ "$score" =~ ^[0-9]+$ ]] || [ "$score" -lt 0 ] || [ "$score" -gt 100 ]; then
        echo "❌ 成绩必须在 0-100 之间"
        return
    fi
    echo "$sid|$name|$course|$score" >> "$GRADES_FILE"
    echo "✅ 成绩已添加"
}

# ── 模糊搜索 ──
search_grade() {
    read -p "输入学号或姓名(支持模糊): " keyword
    results=$(grep -i "$keyword" "$GRADES_FILE")
    if [ -z "$results" ]; then
        echo "未找到匹配记录"
        return
    fi
    echo "$results" | while IFS='|' read -r sid name course score; do
        printf "%-12s %-15s %-10s %-6s\n" "$sid" "$name" "$course" "$score"
    done
    echo "共找到 $(echo "$results" | wc -l) 条记录"
}

# ── 统计 ──
show_stats() {
    echo "===== 成绩统计 ====="
    echo "总人数:    $(wc -l < "$GRADES_FILE")"
    awk -F'|' '{
        sum+=$4; count++;
        if($4>max||count==1) max=$4;
        if($4<min||count==1) min=$4;
        if($4>=60) pass++
    } END {
        printf "平均分:    %.1f\n", sum/count
        printf "最高分:    %d\n", max
        printf "最低分:    %d\n", min
        printf "及格率:    %.1f%%\n", pass/count*100
    }' "$GRADES_FILE"
}

# ── CSV 批量导入 ──
import_csv() {
    read -p "CSV 文件路径: " csv_path
    if [ ! -f "$csv_path" ]; then
        echo "❌ 文件不存在"
        return
    fi
    count=0
    tail -n +2 "$csv_path" | while IFS=',' read -r sid name course score; do
        echo "$sid|$name|$course|$score" >> "$GRADES_FILE"
        ((count++))
    done
    echo "✅ 已导入 $count 条记录"
}

# ── 主菜单 ──
main_menu() {
    while true; do
        echo ""
        echo "===== 成绩管理系统 ====="
        [ "$ROLE" = "teacher" ] && echo "1) 添加成绩   2) 查看成绩"
        [ "$ROLE" = "teacher" ] && echo "3) 搜索成绩   4) 删除成绩"
        [ "$ROLE" = "teacher" ] && echo "5) 批量导入   6) 统计"
        echo "7) 退出"
        read -p "选择: " choice
        case $choice in
            1) [ "$ROLE" = "teacher" ] && add_grade ;;
            2) [ "$ROLE" = "teacher" ] && list_grades ;;
            3) [ "$ROLE" = "teacher" ] && search_grade ;;
            4) [ "$ROLE" = "teacher" ] && delete_grade ;;
            5) [ "$ROLE" = "teacher" ] && import_csv ;;
            6) [ "$ROLE" = "teacher" ] && show_stats ;;
            7) exit 0 ;;
            *) echo "无效选择" ;;
        esac
    done
}

# ── 启动 ──
init
login && main_menu
📁 源文件清单GitHub 仓库 ↗
路径说明行数
grade_manager.shShell 成绩管理系统完整脚本180
网站智能助手
💬 和我聊聊
🤖
你好呀 👋 有什么想聊的?