Linux下按文件名ddmmyyyy日期批量归类图片至yyyy/mm/dd目录
需求与问题描述
我有大量格式如下的图片文件:
randomname_08042020_1837_sometext_somemoretext.jpg randomname_17012022_1650_sometext_somemoretext.th.jpg randomname_08042020_1837_sometext_somemoretext.th.jpg randomname_17012022_1658_sometext_somemoretext.jpg randomname_09042020_0009_sometext_somemoretext.jpg randomname_17012022_1658_sometext_somemoretext.th.jpg randomname_09042020_0009_sometext_somemoretext.th.jpg randomname_17012022_1711_sometext_somemoretext.jpg randomname_15062020_1736_sometext_somemoretext.jpg randomname_17012022_1711_sometext_somemoretext.th.jpg randomname_15062020_1736_sometext_somemoretext.th.jpg randomname_17012022_1719_sometext_somemoretext.jpg randomname_09052020_1812_sometext_somemoretext.jpg randomname_17012022_1719_sometext_somemoretext.th.jpg randomname_09052020_1812_sometext_somemoretext.th.jpg randomname_17012022_1730_sometext_somemoretext.jpg randomname_09052020_1838_sometext_somemoretext.jpg randomname_17012022_1730_sometext_somemoretext.th.jpg randomname_09052020_1838_sometext_somemoretext.th.jpg randomname_17092021_2340_sometext_somemoretext.jpg
需要编写脚本,根据文件名中第一个下划线后的ddmmyyyy格式日期,将图片分类到yyyy/mm/dd结构的文件夹中(需自动创建文件夹)。
之前尝试修改基于sed的脚本但无效,修改后的脚本既不移动文件也不报错:
#!/bin/bash cd /opt/large-out for file in *.jpg; do date=$(printf "$file" | sed -nE 's/.*_([01][0-9])([0-9]{4})([0-3][0-9])([0-9]{4})_.*/\3\/\2\/\1/p') if [ -n "$date" ]; then mkdir -p "$date" && mv "$file" "$date" fi done
问题分析
你修改后的sed正则表达式完全错误,没有匹配到文件名的结构:
- 原文件名中第一个下划线后是
ddmmyyyy(8位数字:日2位+月2位+年4位),比如08042020对应08日 04月 2020年 - 你的正则里错误地捕获了4段数字,和实际的8位ddmmyyyy结构不符,导致匹配失败,
date变量为空,脚本因此没有执行后续操作。
正确脚本方案
以下是适配你文件名格式的两种bash脚本实现:
方案1:sed正则匹配版
#!/bin/bash cd /opt/large-out || exit 1 # 切换目录失败则直接退出 for file in *.jpg *.th.jpg; do # 匹配两种后缀的图片文件 # 捕获第一个下划线后的ddmmyyyy,分组为(dd)(mm)(yyyy),转换为yyyy/mm/dd格式 dir_path=$(echo "$file" | sed -nE 's/^[^_]+_([0-9]{2})([0-9]{2})([0-9]{4})_.*/\3\/\2\/\1/p') if [ -n "$dir_path" ]; then mkdir -p "$dir_path" && mv "$file" "$dir_path" fi done
方案2:纯bash字符串处理版(无需外部工具,效率更高)
#!/bin/bash cd /opt/large-out || exit 1 for file in *.jpg *.th.jpg; do # 按下划线分割文件名,提取第一个下划线后的日期段 date_segment=${file#*_} # 移除第一个下划线及之前的内容 date_segment=${date_segment%%_*} # 移除第二个下划线及之后的内容 # 验证是否为8位数字的日期段 if [[ $date_segment =~ ^[0-9]{8}$ ]]; then dd=${date_segment:0:2} mm=${date_segment:2:2} yyyy=${date_segment:4:4} dir_path="${yyyy}/${mm}/${dd}" mkdir -p "$dir_path" && mv "$file" "$dir_path" fi done
脚本说明
cd /opt/large-out || exit 1:确保切换目录失败时脚本直接退出,避免后续操作出现错误*.jpg *.th.jpg:覆盖所有.jpg和.th.jpg后缀的图片文件- 方案1的sed正则:
^[^_]+_匹配第一个下划线前的任意内容,精准捕获dd、mm、yyyy三段数字并转换为目标路径格式 - 方案2使用bash内置的字符串截取功能,无需调用外部工具,处理大量文件时速度更快
内容的提问来源于stack exchange,提问作者asteroids_r_fun
相关产品推荐
相关产品推荐

