Я пытаюсь автоматически переименовать и отсортировать изображения и видео из экспорта Google Фото (Google Takeout), используя сценарий bash. Структура каталога 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
│ ├── 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
...
Я попытался создать скрипт bash для части переименования, однако он не работает, поскольку, похоже, используется дата последнего редактирования, а не дата создания, несмотря на опцию -r. Не могу понять, как перевести расширение в нижний регистр.
#!/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
Примечания:
*.json и *.ini.Я попытался создать другой bash-скрипт для сортировки, однако он перемещает только файлы, а не каталоги, содержащие эти файлы.
#!/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
Заранее спасибо за помощь!
Чтобы получить дату создания файла, вы можете использовать команду stat следующим образом: date -d @$(stat --format = "%W" "$f") +"%d%m%Y_%H%M%S%2N"
Я не фанат команды cd в скриптах. Вы пытаетесь использовать команду tree? Вот так: tree -if "$1"
Пожалуйста, прочтите добавленный вами тег bash и скопируйте/вставьте свой код на shellcheck.net, исправьте все отмеченные проблемы и обновите свой вопрос (в вашем коде имеется множество проблем). Удачи.
в верхней части вашего скрипта (перед любыми присвоениями ext) вы можете запустить unset ext; declare -l ext (это нужно сделать только один раз в скрипте), чтобы принудительно преобразовать все последующие назначения в ext в нижний регистр.
в первом сценарии bash вы запускаете cd "$d", но никогда не возвращаетесь к тому месту, где вы начали, поэтому при следующем проходе цикла cd "$d" завершится неудачей, потому что вы все еще сидите в $d из предыдущего прохода цикла; также учтите, что for d in * подберет все в текущем каталоге... каталоги, файлы и литерал *, если каталогов/файлов нет, поэтому рассмотрите возможность а) проверки того, что $d является каталогом, или б) заполнения цикла результатами а find . -maxdepth 1 -type d
Я голосую за закрытие этого вопроса, потому что на плакате не использовался shellcheck.net , как указано в теге bash.





Для cd можно использовать подоболочку, вы можете попробовать что-то вроде этого.
#!/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]}"
continue
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/ создается ниже/на одном уровне вашего каталога Google Photo..ini и .json. игнорируются,rm и измените cp на mv, если результат/результат вас устраивает.stat, как указано в комментариях, для даты создания, хотя она может быть недоступна в некоторых ОС/файловых системах.dotglob)cd в subshell включена)*.@(ini|json) glob/шаблона.Впечатляет, это работает! Действительно, похоже, что функция stat не работает при использовании подсистемы Windows для Linux для фиксации даты создания файла, находящегося в каталоге Windows.
Для нижнего регистра используйте простой синтаксис bash, например:
${ext,,}