强大的 exiftool 助 Synology 照片整理一臂之力

↘锁芯ラ 提交于 2020-03-03 21:18:04

安装 exiftool

# 先安装 Perl 套件,然后开启 ssh-server
wget -o ~admin/www/Image-ExifTool-11.89.tar.gz https://exiftool.org/Image-ExifTool-11.89.tar.gz
tar -C ~admin/www -zxvf ~admin/www/Image-ExifTool-11.89.tar.gz
ln -s ~admin/www/Image-ExifTool-11.89/exiftool /usr/local/bin/exiftool
exiftool -ver

体验 exiftool

# 按照片拍摄年份,存入指定目录
exiftool '-Directory<CreateDate' -d "~/photo/%Y" ./*.{jpg,cr2,heic}
# 文件按格式改名
exiftool '-filename<CreateDate' -d "%Y/%Y%m%d-%H%M%S.%%le" ./*.{jpg,heic,cr2}
# 自带调试(只读打印)
exiftool '-testname<CreateDate' -d "%Y/%Y%m%d-%H%M%S.%%le" -r ~/photo

用后感 exiftool

exiftool 虽然强大,建议当工具使用。不少定制化的需求无法满足:

  • 1、默认 -o 拷贝的时候,遇到没有源信息文件 会全堆在一块(异常图片处理不好)
  • 2、不带文件重名覆盖的选项(遇到重复会改名,没有其它逻辑)
  • 3、不支持目录排除(递归查找无法排除)
  • 4、不输出改名后的信息,无法记录(输出信息少,嵌入脚本使用不友好)
  • 5、改名/移动 功能不错,复制设计不足(宝贵的图片源稿不到最后不删、不动)
  • 好在 exiftool 能补足 exiv2 功能上的不足,一行命令就能修复未识别的文件:
find ~/Drive/Moments/Mobile ~/Drive/Backup/MobileDevice ! -path "*@eaDir*" -type f -iname "*.heic" -o -iname "*.cr2" -exec exiftool '-filename<CreateDate' -d "%Y%m%d-%H%M%S.%%le" {} \;
  • 最终为了照片的数据安全,还是写脚本来整理照片吧
#/bin/bash
# while read -r fName; do touch "./${fName}"; done < Sample.txt
readonly debug=false # 调试开关
fList="${1:-/volume1/homes/higkoo/XiaoMi/Image/FileList.csv}" 
dDir="${2:-/volume1/homes/higkoo/XiaoMi/Image/}" # 归档目录
readonly eLog="${dDir}Error.log"
declare -A sInfo=([c]="0:0" [t]="2000-11-22 11:22:33" [s]="/dev/zero" [d]="/dev/null")  # 用于存行信息
declare -A dInfo=([Y]=2000 [m]=11 [d]=22 [H]=11 [M]=22 [S]=33 [p]="/dev/null")  # 解析文件名信息
declare -r mCode=([0]="Noneed" [1]="Created" [2]="Exsit" [3]="Overwrite" [4]="Failed" [5]="Error" [6]="Unknow")  # 错误码定义
declare -a dDirList=() # 减少文件操作,用内存操作替换
rCode=6 # 错误码
IFS=',' # 设定分隔符,read 行的同时完成解析
grep -nE '^0.*heic|^0.*HEIC' "${fList}" | while read -r sInfo[c] sInfo[t] sInfo[s] sInfo[d] ; do
   unset lNum # 重置变量,避免异常时循环的数据污染
   lNum="${sInfo[c]%:*}" # 此串在源文件所在的行号,方便 sed 使用
   sCode="${sInfo[c]#*:}" # 此行第1列,错误码
   sPath="${sInfo[s]}" # 文件源路径
   dPath="${sInfo[d]}" # 文件新路径
   sfName="${sPath##*/}" # 文件名(带后缀)
   spName="${sfName%.*}" # 文件名(无后缀)
   stStr="${spName#* }" # 时分秒串
   sExt="${sfName##*.}" # 后缀名

   if [ "${sfName:10:1}" = " " -a ${#spName} -eq 17 ]; then # 文件名时间串,视为可信
       read dInfo[Y] dInfo[m] dInfo[d] dInfo[H] dInfo[M] dInfo[S] < <(date -d "${spName% *} ${stStr:0:2}:${stStr:2:2}:${stStr:4:2}" +"%Y,%m,%d,%H,%M,%S") 2>>"${eLog}"
       dfName="${spName//-/}" && dfName="${dfName// /-}.${sExt,,}"
       dInfo[p]="${dDir}${dInfo[Y]}/${dfName}"
       nPath="${sPath%/*}/${dfName}" # 新文件名
   else # 从文件 Meta 信息读拍摄时间,拼接目标文件全路径
       dInfo[p]=`exiftool -d "${dDir}%Y/%Y%m%d-%H%M%S.${sExt,,}" -DateTimeOriginal -S -s "${sInfo[s]"` 2>>"${eLog}"
       dInfo[Y]="${dInfo[p]:${#dDir}:4}"
       nPath="${sPath%/*}/${dInfo[p]##*/}" # 新文件名
   fi
   mv -v "${sPath}" "${nPath}" 2>>"${eLog}" && sed -i "${lNum}s/${sPath##*/}/${dInfo[p]##*/}/" "${fList}" || rCode=4 # 更新日志
   if [[ ! ${dDirList[*]} =~ (^|[[:space:]])"${dInfo[Y]}"($|[[:space:]]) ]]; then # 按需创建目录
       mkdir -pv "${dDir}${dInfo[Y]}/" && dDirList+=("${dInfo[Y]}")
   fi
   if [[ ! -f "${dInfo[p]}" ]]; then # 拷贝到备份目录
       cp -v "${nPath}" "${dInfo[p]}" 2>>"${eLog}" && rCode=1 || rCode=4
   else
       if [[ `stat --printf=%s "${dInfo[p]}"` -lt `stat --printf=%s "${nPath}"` ]]; then  
            cp -v "${nPath}" "${dInfo[p]}" 2>>"${eLog}" && rCode=3 || rCode=4
       else
           rCode=2 && echo -ne '-'  # 文件存在且比源文件大,跳过
       fi
   fi
   sed -i "${lNum}s/^${sCode},${sInfo[t]}/${rCode},`date +%F\ %T`/" "${fList}" 2>>"${eLog}" # 更新文件状态和时间
   $debug && declare -p sInfo dInfo
   sInfo=() # 用完清空
   dInfo=() # 垃圾回收
exit 0
done
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!