如何编写Shell脚本批量按规则压缩日期命名的文件夹?
嘿,这个需求我之前碰到过类似的,给你写个实用的Shell脚本,顺便拆解下逻辑,保证你能看懂也能复用~
核心思路
咱们要解决的问题分两步:
- 按月份分组:因为要求每个月内的文件夹单独处理,不能跨月打包;
- 每3个一组打包:每个月里的文件夹按日期排序后,每凑够3个就打包,剩下不足3个的也单独打包,文件名要包含组内第一个和最后一个文件夹的日期(和你给的示例格式一致)。
完整脚本
直接把下面的代码保存成pack_daily_folders.sh就行:
#!/bin/bash # 获取当前目录下所有符合YYYYMMDD格式的文件夹,按日期排序 folders=$(ls -d [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/ 2>/dev/null | sort) # 如果没有找到符合条件的文件夹,直接退出 if [ -z "$folders" ]; then echo "⚠️ 没有找到符合YYYYMMDD格式的日期文件夹" exit 1 fi # 按月份分组,每3个文件夹打包一次 echo "$folders" | awk ' BEGIN { current_month = "" group = [] group_count = 0 } { # 去掉文件夹名末尾的斜杠,提取月份(前6位:YYYYMM) folder = $0 sub(/\/$/, "", folder) month = substr(folder, 1, 6) # 切换月份时,先处理上一个月份剩余的文件 if (month != current_month) { if (current_month != "" && group_count > 0) { pack_group(group, group_count) } current_month = month delete group group_count = 0 } # 将当前文件夹加入组 group[++group_count] = folder # 每凑够3个就打包 if (group_count == 3) { pack_group(group, group_count) delete group group_count = 0 } } END { # 处理最后一个月份剩余的不足3个的文件 if (group_count > 0) { pack_group(group, group_count) } } # 打包函数:生成文件名并执行tar命令 function pack_group(arr, cnt, first, last, tar_name, cmd) { first = arr[1] last = arr[cnt] # 生成和示例一致的文件名:同月的话后面的日期只保留后两位 if (substr(first, 1, 6) == substr(last, 1, 6)) { tar_name = "mytar-" first "_" substr(last, 7) ".tar.bz2" } else { tar_name = "mytar-" first "_" last ".tar.bz2" } # 构建tar命令 cmd = "tar jcvf " tar_name " " for (i=1; i<=cnt; i++) { cmd = cmd arr[i] " " } print "✅ 执行打包命令:" cmd system(cmd) } '
脚本关键部分解释
文件夹筛选与排序:
ls -d [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/:精准匹配8位数字命名的文件夹;sort:因为YYYYMMDD格式的字符串直接排序就是日期顺序,完美解决日期不连续的问题。
按月份分组逻辑:
- 用
current_month变量跟踪当前处理的月份(前6位字符),一旦月份变化,就先把上一个月剩余的文件夹打包,再切换到新月份。
- 用
打包文件名生成:
- 如果组内所有文件夹都在同一个月,文件名就用
mytar-YYYYMMDD_XXDD.tar.bz2的格式(比如你示例里的mytar-20171002_1005.tar.bz2); - 极端情况如果跨月(不过脚本已经按月份分组,这种情况不会出现),会生成完整的日期拼接文件名。
- 如果组内所有文件夹都在同一个月,文件名就用
使用注意事项
- 给脚本加执行权限:
chmod +x pack_daily_folders.sh; - 测试阶段可以先把
system(cmd)这一行注释掉,只看打印出来的命令,确认没问题再执行实际打包; - 如果你的文件夹不在当前目录,可以修改
ls命令的路径,比如ls -d /path/to/your/folders/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/。
内容的提问来源于stack exchange,提问作者user9624737
相关产品推荐
相关产品推荐

