Переименовывайте и сортируйте изображения и видео из Google Takeout

Я пытаюсь автоматически переименовать и отсортировать изображения и видео из экспорта 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

Примечания:

  1. Мне нужно использовать миллисекунды, чтобы избежать удаления файлов, если они были сняты в одну и ту же секунду.
  2. Я хотел бы удалить все файлы *.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

Заранее спасибо за помощь!

Для нижнего регистра используйте простой синтаксис bash, например: ${ext,,}

Arnaud Valmary 28.07.2024 15:50

Чтобы получить дату создания файла, вы можете использовать команду stat следующим образом: date -d @$(stat --format = "%W" "$f") +"%d%m%Y_%H%M%S%2N"

Arnaud Valmary 28.07.2024 15:51

Я не фанат команды cd в скриптах. Вы пытаетесь использовать команду tree? Вот так: tree -if "$1"

Arnaud Valmary 28.07.2024 15:53

Пожалуйста, прочтите добавленный вами тег bash и скопируйте/вставьте свой код на shellcheck.net, исправьте все отмеченные проблемы и обновите свой вопрос (в вашем коде имеется множество проблем). Удачи.

shellter 28.07.2024 16:33

в верхней части вашего скрипта (перед любыми присвоениями ext) вы можете запустить unset ext; declare -l ext (это нужно сделать только один раз в скрипте), чтобы принудительно преобразовать все последующие назначения в ext в нижний регистр.

markp-fuso 28.07.2024 17:25

в первом сценарии bash вы запускаете cd "$d", но никогда не возвращаетесь к тому месту, где вы начали, поэтому при следующем проходе цикла cd "$d" завершится неудачей, потому что вы все еще сидите в $d из предыдущего прохода цикла; также учтите, что for d in * подберет все в текущем каталоге... каталоги, файлы и литерал *, если каталогов/файлов нет, поэтому рассмотрите возможность а) проверки того, что $d является каталогом, или б) заполнения цикла результатами а find . -maxdepth 1 -type d

markp-fuso 28.07.2024 17:28

Я голосую за закрытие этого вопроса, потому что на плакате не использовался shellcheck.net , как указано в теге bash.

Ed Morton 28.07.2024 19:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для 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 (cd в subshell включена)
  • См. Проверка/сравнение значения переменной несколько раз для *.@(ini|json) glob/шаблона.

Впечатляет, это работает! Действительно, похоже, что функция stat не работает при использовании подсистемы Windows для Linux для фиксации даты создания файла, находящегося в каталоге Windows.

dddroog 28.07.2024 21:41

Другие вопросы по теме