请求优化Google Takeout照片视频的Bash重命名与排序脚本
Google Takeout照片/视频自动重命名与整理脚本优化
原目录结构(Google Photos导出)
. ├── Google Photos │ ├── Accident Mercedes │ │ ├── IMG_9660.JPG │ │ ├── IMG_9660.JPG.json │ │ └── metadata.json │ ├── Ardennen vrienden Ine │ │ ├── 0906b711-2fc6-4b29-8daf-1203aad2f2ca.jpg │ │ ├── 0906b711-2fc6-4b29-8daf-1203aad2f2ca.jpg.json │ │ ├── 41ADBC31-C2FB-4489-A316-81464EA04F18.mp4 │ │ ├── 41ADBC31-C2FB-4489-A316-81464EA04F18.mp4.json │ │ ├── IMG_0414.JPG │ │ ├── IMG_0414.JPG.json │ │ └── metadata.json │ ├── Audi Q3 Ine │ │ ├── IMG_5602.JPG │ │ ├── IMG_5602.JPG.json │ │ ├── IMG_5614.MOV │ │ ├── IMG_5614.MOV.json │ │ └── metadata.json ...
期望最终效果
文件名格式为 %d%m%Y_%H%M%S%2N.lower_case_extension,按年份+原相册目录分组,分为Photo/Video主目录:
. ├── Photo │ ├── 2022 │ │ ├── Accident Mercedes │ │ │ ├── 17052022_15563312.jpg │ │ │ ├── 17052022_15563817.jpg │ │ │ ├── 17052022_15564918.jpg │ │ ├── Ardennen vrienden Ine │ │ │ ├── 20072022_21241609.jpg │ │ │ ├── 20072022_21292212.jpg │ │ │ ├── 20072022_21310924.jpg ├── Video │ ├── 2022 │ │ ├── Accident Mercedes │ │ │ ├── 17052022_15563316.mp4 │ │ │ ├── 17052022_15563818.mov │ │ ├── Ardennen vrienden Ine │ │ │ ├── 20072022_21241645.mp4 ...
现有脚本的问题
- 重命名脚本使用文件修改时间而非拍摄时间(即使加了
-r参数),且无法将扩展名转为小写 - 排序脚本仅能移动文件,无法保留原相册的目录结构
- 未处理同秒拍摄文件的重复覆盖问题,也未自动清理冗余的
*.json和*.ini文件
优化后的完整脚本
#!/bin/bash # 检查输入参数 if [ $# -ne 2 ]; then echo "用法: $0 <Google Photos源目录> <输出根目录>" exit 1 fi SOURCE_DIR="$1" OUTPUT_ROOT="$2" # 定义照片/视频扩展名 PHOTO_EXTS=("jpg" "jpeg" "heic" "png") VIDEO_EXTS=("mp4" "mov" "avi" "mkv") # 创建主目录 mkdir -p "${OUTPUT_ROOT}/Photo" "${OUTPUT_ROOT}/Video" # 遍历源目录下的所有相册子目录 for ALBUM_DIR in "${SOURCE_DIR}"/*; do if [ ! -d "${ALBUM_DIR}" ]; then continue fi ALBUM_NAME=$(basename "${ALBUM_DIR}") echo "处理相册: ${ALBUM_NAME}" # 删除当前相册下的json和ini文件 rm -f "${ALBUM_DIR}"/*.json "${ALBUM_DIR}"/*.ini # 遍历当前相册下的所有媒体文件 for FILE in "${ALBUM_DIR}"/*; do if [ ! -f "${FILE}" ]; then continue fi # 获取文件名和扩展名(转为小写) FILE_EXT=$(echo "${FILE##*.}" | tr '[:upper:]' '[:lower:]') FILE_NAME=$(basename "${FILE}") # 判断是照片还是视频 MEDIA_TYPE="" if [[ " ${PHOTO_EXTS[@]} " =~ " ${FILE_EXT} " ]]; then MEDIA_TYPE="Photo" elif [[ " ${VIDEO_EXTS[@]} " =~ " ${FILE_EXT} " ]]; then MEDIA_TYPE="Video" else echo "跳过非媒体文件: ${FILE_NAME}" continue fi # 从文件元数据中提取拍摄时间(优先用EXIF/创建时间) # 用exiftool获取拍摄时间,若失败则回退到文件修改时间 if command -v exiftool &> /dev/null; then # 照片用DateTimeOriginal,视频用CreateDate if [ "${MEDIA_TYPE}" = "Photo" ]; then TIMESTAMP=$(exiftool -d "%d%m%Y_%H%M%S%2N" -DateTimeOriginal -s3 "${FILE}") else TIMESTAMP=$(exiftool -d "%d%m%Y_%H%M%S%2N" -CreateDate -s3 "${FILE}") fi fi # 如果exiftool没获取到时间,用文件修改时间 if [ -z "${TIMESTAMP}" ]; then TIMESTAMP=$(date -r "${FILE}" +"%d%m%Y_%H%M%S%2N") echo "警告: 无法获取${FILE_NAME}的拍摄时间,使用修改时间" fi # 提取年份(用于目录分组) YEAR=$(echo "${TIMESTAMP}" | cut -c 5-8) # 构建目标路径 TARGET_DIR="${OUTPUT_ROOT}/${MEDIA_TYPE}/${YEAR}/${ALBUM_NAME}" mkdir -p "${TARGET_DIR}" # 构建新文件名 NEW_FILENAME="${TIMESTAMP}.${FILE_EXT}" # 处理重复文件名(如果同名则加后缀) COUNT=1 while [ -f "${TARGET_DIR}/${NEW_FILENAME}" ]; do NEW_FILENAME="${TIMESTAMP}_${COUNT}.${FILE_EXT}" COUNT=$((COUNT + 1)) done # 移动并重命名文件 mv "${FILE}" "${TARGET_DIR}/${NEW_FILENAME}" echo "已处理: ${FILE_NAME} -> ${TARGET_DIR}/${NEW_FILENAME}" done done echo "所有媒体文件处理完成!"
脚本说明
- 依赖:需要安装
exiftool(用于准确提取拍摄时间),Debian/Ubuntu可通过sudo apt install libimage-exiftool-perl安装 - 拍摄时间优先:优先从EXIF元数据提取拍摄时间,避免用文件修改时间导致的错误
- 扩展名小写:通过
tr '[:upper:]' '[:lower:]'统一转为小写格式 - 目录结构保留:自动创建
Photo/年份/原相册名和Video/年份/原相册名的层级目录 - 重复文件处理:同秒同毫秒的文件会自动加数字后缀,彻底避免覆盖
- 冗余文件清理:自动删除源目录下的所有
*.json和*.ini文件
使用方法
# 给脚本添加执行权限 chmod +x organize_photos.sh # 运行脚本,第一个参数是Google Photos源目录,第二个是输出目录 ./organize_photos.sh "/path/to/Google Photos" "/path/to/Output"
内容的提问来源于stack exchange,提问作者dddroog
相关产品推荐
相关产品推荐

