I'm trying to automatically rename and sort pictures and videos from a Google Photos export (Google Takeout) using a bash script. Structure of the Google Photos directory after download:
.
├── 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
...
End result I would like to achieve, where the filename is formatted like %d%m%Y_%H%M%S%2N.lower_case_extension
and the directories are grouped per year and split over two main video and photo directories:
.
├── 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
...
I've tried creating a bash script for the renaming part, however it's not working, since it seems to use last edit date and not creation date, despite -r
option. Unable to figure out how to lowercase the extension.
#!/bin/bash
cd "$1"
for d in *; do
cd "$d"
for f in *.jpg *.JPG *.MOV *.mov *.mp4 *.MP4 *.heic; do
echo "./$d/$f"
new_name=$(date -r "$f" +"%d%m%Y_%H%M%S%2N")
ext="${f##*.}"
mv "$f" "${new_name}.${ext}"
done
rm -rf "*.desktop.ini"
rm -rf "*.json"
done
Remarks:
*.json
and *.ini
files.I've tried creating another bash script for the sorting part, however it's only moving files and not directories containing those files.
#!/bin/bash
cd "$1"
mkdir Video
cd Video
mkdir -p {2000..2024}
c=2000
while [ $c -lt 2024 ]; do
find "$2" -iname "*$c_*.jpg" -print0 | xargs -0 -I {} mv {} ./$c
let c=c+1
done
cd "$1"
mkdir Photos
cd Photos
mkdir -p {2000..2024}
c=2000
while [ $c -lt 2024 ]; do
find "$2" -iname "*$c_*.mp4" -print0 | xargs -0 -I {} mv {} ./$c
let c=c+1
done
Thanks in advance for help!
A subshell can be used for the cd
, you could try something like this.
#!/usr/bin/env bash
shopt -s nullglob
GooglePhotos=(Google\ Photos/*/)
shopt -u nullglob
for d in "${GooglePhotos[@]}" ; do
cwd=
ext=
file_type=
mod_year=
old_file_name=
new_file_name=
declare -a files
(
cd "$d" || exit
shopt -s nullglob
files=(*)
shopt -u nullglob
for f in "${!files[@]}"; do
if [[ "${files[$f]}" == *.@(ini|json) ]]; then
# rm -rf -- "${files[$f]}"
break
else
ext=${files[$f]##*.}
ext=${ext,,}
old_file_name="${files[$f]}"
cwd="$(basename -- "$PWD")"
mod_year="$(date -r "${files[$f]}" '+%Y')"
file_type="$(file --mime-type -b -- "${files[$f]}")"
new_file_name="$(date -r "${files[$f]}" '+%d%m%Y_%H%M%S%2N').${ext}"
if [[ "$file_type" == video/* ]]; then
mkdir -pv "../Google/Video/$mod_year/$cwd" || exit
cp -v -- "$old_file_name" "../Google/Video/$mod_year/$cwd/$new_file_name" || exit
elif [[ "$file_type" == image/* ]]; then
mkdir -pv "../Google/Photo/$mod_year/$cwd/" || exit
cp -v -- "$old_file_name" "../Google/Photo/$mod_year/$cwd/$new_file_name" || exit
fi
fi
unset -v 'files[f]'
done
files=("${files[@]}")
)
done
Google/
is created below/one level of your Google Photo
directory..ini
and .json
. are ignored,rm
and change cp
to mv
if satisfied with the output/outcome/result.stat
as mentioned in the comments for the creation date, although it might not be available on some os/file system.dotglob
also)cd
in a subshell
included)*.@(ini|json)
glob/pattern.