Linux Shell脚本作业文件分类故障:仅解压无后续分类操作
问题描述
submissions文件夹里存着多个zip文件,每个zip包含若干子文件夹和文件。我需要实现这些操作:
- 从zip文件名里提取学生ID
- 创建目标文件夹结构
- 解压zip后,把C、Python、Java文件按扩展名分类,重命名为main.c/main.py/Main.java,分别移到targets/C、targets/Python、targets/Java目录下对应学生ID的子文件夹里
但现在脚本只能把zip文件解压到submissions文件夹,后续的分类动作完全没执行,找不到问题出在哪。
现有脚本代码
#!/bin/bash # Create target directory mkdir targets # Create subdirectories for C, Python, and Java mkdir targets/C mkdir targets/Python mkdir targets/Java # Loop through all files in submissions directory for file in submissions/*.zip do # Extract the contents of the zip file unzip "$file" -d /home/goat/Desktop/Jaid/'CSE 314'/'Offline 1'/Workspace/submissions # Get the student ID from the file name student_id=${file: -11:7} #echo $student_id visit() { if [ -d $1 ] then for i in $1/* do visit "$i" done elif [ -f $1 ] then #echo $1 # Get the file extension file_extension=${1: -1} # Check if the file extension is C, Python, or Java # for c if [ "$file_extension" == "c" ] then # Copy the C file to the targets/C directory cp "$1" targets/C/"$student_id"/main.c #for py elif [ "$file_extension" == "y" ] then # Copy the Python file to the targets/Python directory cp "$1" targets/Python/"$student_id"/main.py #for java elif [ "$file_extension" == "a" ] then # Copy the Java file to the targets/Java directory cp "$1" targets/Java/"$student_id"/Main.java fi fi } visit submissions # Remove the extracted files #rm -rf "$file" done
问题排查与修复方案
现有脚本存在几个关键问题,导致分类动作失效:
函数定义位置错误:visit函数在for循环内部定义,每次循环都会重新定义函数,bash中函数定义后需要重新解析才生效,直接调用会引发作用域问题。应该把函数移到循环外面定义。
扩展名提取完全错误:
${1: -1}只取了文件名最后一个字符,比如.py文件最后一个字符是y,根本不是扩展名。正确做法是用${1##*.}获取文件名最后一个点之后的完整扩展名。目标子文件夹未创建:直接执行
cp到targets/C/$student_id,但这个文件夹不存在,cp会报错退出,导致文件无法复制。需要先创建对应文件夹。遍历范围错误:调用
visit submissions会遍历整个submissions目录,包括之前解压的其他学生文件,容易重复处理。应该只遍历当前zip解压出来的内容。硬编码路径:unzip的-d参数用了绝对路径,脚本移植性差,换成相对路径或临时目录更合理。
修复后的脚本
#!/bin/bash # 定义递归遍历函数,接收当前路径和学生ID参数 visit() { local current_path="$1" local student_id="$2" if [ -d "$current_path" ]; then # 遍历目录下的所有项 for item in "$current_path"/*; do visit "$item" "$student_id" done elif [ -f "$current_path" ]; then # 获取文件扩展名并转为小写,兼容大小写差异(比如.C/.PY) local file_extension=$(echo "${current_path##*.}" | tr '[:upper:]' '[:lower:]') # 根据扩展名分类处理 case "$file_extension" in c) local target_dir="targets/C/$student_id" mkdir -p "$target_dir" # -p确保父目录不存在时自动创建 cp "$current_path" "$target_dir/main.c" ;; py) local target_dir="targets/Python/$student_id" mkdir -p "$target_dir" cp "$current_path" "$target_dir/main.py" ;; java) local target_dir="targets/Java/$student_id" mkdir -p "$target_dir" cp "$current_path" "$target_dir/Main.java" ;; esac fi } # 创建目标目录结构,-p参数避免目录已存在时报错 mkdir -p targets/C targets/Python targets/Java # 遍历submissions下的所有zip文件 for zip_file in submissions/*.zip; do # 如果没有匹配到zip文件,直接跳过 [ -f "$zip_file" ] || continue # 提取学生ID(按原逻辑取文件名最后11位中的前7位,可根据实际文件名调整) local student_id="${zip_file: -11:7}" # 创建临时目录存放当前zip的解压内容,避免干扰其他文件 local temp_dir="temp_$student_id" mkdir -p "$temp_dir" # 静默解压zip到临时目录 unzip -q "$zip_file" -d "$temp_dir" # 遍历临时目录中的文件,执行分类操作 visit "$temp_dir" "$student_id" # 清理临时解压目录 rm -rf "$temp_dir" done
修复说明
- 把visit函数移到循环外,通过参数传递学生ID,避免依赖全局变量导致的问题
- 用
${current_path##*.}正确提取完整扩展名,同时转小写处理大小写不一致的情况 - 使用
mkdir -p确保目标子文件夹存在,不会因为目录不存在导致复制失败 - 新增临时目录存放当前zip的解压内容,避免遍历整个submissions目录,处理完后直接清理,保持目录整洁
- 添加了空判断,避免submissions下没有zip文件时脚本报错
- unzip添加
-q参数实现静默解压,减少不必要的输出
内容的提问来源于stack exchange,提问作者Jaid Chowdhury
相关产品推荐
相关产品推荐

