巧用 bash 变量的正则匹配功能,实现海量文件名的格式化

浪尽此生 提交于 2020-03-07 00:40:26

写在前面

  • 疫情期间整理 Synology 里存储了10多年的相片,这些相片穿越了功能手机到智能手机的年代。
  • 不少照片非常有年代感,文件名同样也有年代感。五花八门……
  • 最初用 exiv2 来读取照片的源信息,发现有些老照片没有源信息、新格式的照片读不到源信息。
  • 然后用 exiftool 来识别了新照片的源信息和部分视频的源信息。
  • 最后甚至还启用了 SQLite 数据库存储文件的源信息。

化繁为简

  • 今日扫描了一遍文件系统,结合 SQLite 里的数据分析,发现仍有大量 照片/视频 的拍摄时间无法确定:
  1. 部分手机拍摄的全景照片
  2. 部分第三方拍照软件
  3. 从第三方软件另存的照片
  4. 部分视频文件
  5. 很久很久以前的照片
  • 这些都是最美好的记忆,我要保存好它。所以我决定写个脚本去识别那个“乌七八糟”不规则的文件名,哪怕会有些不需要的照片也被整理进来。
  • 总比把珍贵的照片现在就丢失了的好,未来还可以用图片识别去分类、去重,最终无法用程序处理的再人肉处理。想想都完美~  
  • 好,开始动手敲:
#!/bin/bash
# Rename.sh : Foramt the file name by rules
readonly iLog="./Rename.log"  # 扫描日志
readonly eLog="./Rename.err"
readonly debug=false
readonly stdName="(^|[[:space:]])[2,1][0,9][0,1,2,7,9][0-9][0-1][0-9][0-3][0-9]-[0-2][0-9][0-5][0-9][0-5][0-9]($|[[:space:]])" # 标准格式
readonly er1Name="[0,3-9][0-9]{16,}" # 超长数字,提前过滤避免被错误解析
readonly er2Name="[0-9]{18,}" # 异长数字,提前过滤避免被错误解析
readonly er3Name="(^|[[:space:]])-[0-9]{6,}" # 长负数,提前过滤避免被错误解析
readonly minTime=$(date -d '2000-01-11 22:33:44' +%s) # 不存在比这个时间更早的文件
readonly nt1Name="[2,1][0,9][0,1,7,9][0-9][0-1][0-9][0-3][0-9]_[0-2][0-9][0-5][0-9][0-5][0-9]" # 包含 20090516_105959
readonly nt2Name="[2,1][0,9][0,1,7,9][0-9][0-1][0-9][0-3][0-9][0-2][0-9][0-5][0-9][0-5][0-9]" # 包含 20180916112233
readonly nt3Name="[2,1][0,9][0,1,7,9][0-9]_[0-1][0-9]_[0-3][0-9]_[0-2][0-9]_[0-5][0-9]_[0-5][0-9]" # 包含 2018_09_16_11_22_33
readonly nt4Name="[2,1][0,9][0,1,7,9][0-9]-[0-1][0-9]-[0-3][0-9] [0-2][0-9][0-5][0-9][0-5][0-9]" # 包含 2009-05-16 223344
readonly nt5Name="[2,1][0,9][0,1,7,9][0-9]-[0-1][0-9]-[0-3][0-9]-[0-2][0-9]-[0-5][0-9]-[0-5][0-9]" # 包含 2018-09-16-11-22-33
readonly secName="[1,9][0-9]{8,9}" # 包含秒级时间戳,支持2000年之后
find /volume1/homes/{higkoo,anglix}/Drive/{Backup,Moments} ! -path "*@eaDir*" -type f | while read -r sPath; do
       unset fName fExt nName rCode rMove tStr
       fExt="${sPath##*.}"
       [[ ${fExt,,} =~ "png" ]] && continue # 丢弃截图
       [[ ${sExt,,} == "jpeg" ]] && sExt='jpg'  # 将jpeg后缀改为jpg
       fName="${sPath##*/}" && fName="${fName%%.*}"
       if [[ $fName =~ $stdName ]]; then  # case 的正则弱于 [[ ]] ,所以这里使用 if 嵌套
               rCode=0 && rMove=false && echo -ne '.'
       elif [[ $fName =~ $er1Name || $fName =~ $er2Name || $fName =~ $er3Name ]]; then
               rCode='A' && rMove=false && echo -ne '#'
               echo "$sPath" >> ${eLog}
       elif [[ $fName =~ $nt1Name ]]; then
               rCode=1 && rMove=true && echo -ne "$rCode"
               nName="${BASH_REMATCH[0]/_/-}"
       elif  [[ $fName =~ $nt2Name ]]; then
               rCode=2 && rMove=true && echo -ne "$rCode"
               nName="${BASH_REMATCH[0]:0:8}-${BASH_REMATCH[0]:8:6}"
       elif  [[ $fName =~ $nt3Name ]]; then
               rCode=3 && rMove=true && echo -ne "$rCode"
               nName="${BASH_REMATCH[0]//_/}" && nName="${nName:0:8}-${nName:8:6}"
       elif  [[ $fName =~ $nt4Name ]]; then
               rCode=4 && rMove=true && echo -ne "$rCode"
               nName="${BASH_REMATCH[0]//-/}" && nName="${nName/ /-}"
       elif  [[ $fName =~ $nt5Name ]]; then
               rCode=5 && rMove=true && echo -ne "$rCode"
               nName="${BASH_REMATCH[0]//-/}" && nName="${nName:0:8}-${nName:8:6}"
       elif [[ $fName =~ $secName ]]; then
               tStr="${BASH_REMATCH[0]}"
               if [[ $tStr -le $minTime || $tStr -ge $(date +%s) ]]; then
                       rCode='B' && rMove=false && echo -ne '-'
                       echo "$sPath" >> ${eLog}
               else
                       rCode=8 && echo -ne "$rCode"
                       nName="$(date -d @$tStr +%Y%m%d-%H%M%S)"
               fi
       else
               rCode='E' && echo -ne '*'
               echo "$sPath" >> ${eLog}
               continue
       fi
       $rMove && mv -v "${sPath}" "${sPath%/*}/${nName}.${fExt,,}" >>${iLog} 2>>${eLog}
       $debug && declare -p rCode BASH_REMATCH && exit 0
done  
  • 脚本很快就跑完了,成功找回近 7657 张相片/视频。
  • 还剩下两千多张,看了下文件名确实无法判断。后期人肉处理,先开心一会~
    代码调试现成
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!