linux 文件系统中 stat 命令通常无法稳定获取创建时间(btime),应改用 %y(mtime)作为替代;推荐用 date -d "$(stat -c "%y" "$file")" "+%y%m%d_%h%m%s" 安全提取并格式化时间戳,再结合 ${file##*/} 和计数防重名完成批量重命名。

用 stat + mv 循环提取创建时间(birth time)
Linux 文件系统(如 ext4、XFS)理论上支持创建时间(btime),但 stat 命令默认不显示它,且很多发行版的 stat 不支持 %w(birth time)或返回“-”。实际能稳定获取的是修改时间(%y)或状态变更时间(%z)。如果你真需要“创建时间”,先确认是否可用:stat -c "%w" file.jpg。若输出为空或“-”,说明内核/文件系统未暴露该字段,此时应改用 %y(mtime)——对照片而言,通常就是拍摄后首次写入的时间,最接近真实创建时刻。
-
stat -c "%y" file.jpg输出形如2024-05-21 14:23:08.123456789 +0800,需截取前19位并替换空格和冒号 - 推荐统一用
date -d "$(stat -c "%y" "$file")" "+%Y%m%d_%H%M%S"转换,date能正确解析stat的输出格式,比手动字符串切片更可靠 - 注意:文件名含空格或特殊字符时,
for file in *.jpg可能出错,必须加双引号:"$file"
安全执行前先用 echo 预览效果
批量重命名一旦出错很难回退,尤其涉及时间戳时容易因命令逻辑错误导致所有文件变成同一时间名(比如变量未递增、date 调用位置错误)。务必先跳过 mv,只打印将要执行的命令:
for file in *.jpg; do
ts=$(date -d "$(stat -c "%y" "$file")" "+%Y%m%d_%H%M%S" 2>/dev/null)
echo mv "$file" "${ts}_${file##*/}"
done
- 如果某文件
stat -c "%y"失败(比如权限不足),2>/dev/null防止date报错中断整个循环 -
${file##*/}是 Shell 参数扩展,等价于basename "$file",确保只操作文件名部分,不误触路径 - 预览无误后,把
echo mv换成mv再执行
处理同秒创建的多个文件避免覆盖
同一秒拍多张照片很常见,直接用时间戳命名会导致后生成的文件覆盖先生成的。解决方法不是加随机数(破坏可追溯性),而是引入序号补丁:
- 先按时间戳分组:
stat -c "%y %n" *.jpg | sort | awk '{print $1" "$2" "$3}'查看哪些文件共享相同秒级时间 - 在循环中用关联数组记录每个时间戳已出现次数:
declare -A count,每次生成新名前((count[$ts]++)),然后拼接${ts}_$(printf "%02d" ${count[$ts]}).jpg - 更简单做法:直接用
find+stat+sort排序后用行号:find *.jpg -print0 | xargs -0 stat -c "%y %n" | sort | awk '{printf "mv \"%s\" \"img_%s_%03d.jpg\"\n", $NF, $1"_"$2, NR}' | sh(慎用,需验证路径安全)
别忽略时区和文件系统限制
你看到的 stat -c "%y" 时间是本地时区,但照片 EXIF 中的拍摄时间通常是 UTC 或设备设定时区。如果用 exiftool 提取更准的拍摄时间,得额外安装并处理依赖。而多数用户直接用 stat 已足够——只要整批照片都在同一台机器上写入,时区一致性就有保障。
- ext2/ext3 不存创建时间;Btrfs/XFS 支持但需内核 ≥4.11 且挂载选项启用;普通用户几乎无法控制
- 不要依赖
touch -d反向设置时间来“修复”创建时间,那只是改了 atime/mtime,btime 依然不可写 - 如果目标是归档整理,建议优先用
exiftool "-FileName<datetimeoriginal>,这才是面向照片的正解(需安装 exiftool)</datetimeoriginal>











