Для хранения базы своих фотографий раньше использовал пакетную обработку от XnView. Сегодня решил написать скрипт, который будет автоматически разбрасывать мои фотографии в определенную папку с разброской в подпапки по годам.
Имеем Ubuntu 16.04. Для работы скрипта группировки нам понадобится exiv2 и imagemagick. Для их установки выполните команду:
sudo apt-get install exiv2 imagemagick
Далее, приведу сам скрипт с комментариями по ходу
#!/bin/bash # Скрипт раскладывает фотографии по каталогам вида гггг/мм, изменяет разрешение и качество в # соответствии с заданными параметрами, а так же переименовывает изображения в формат # гггг-мм-дд_чч-мм-сс.jpg # На пример: /mnt/DCIM/IMG-20131014112354.jpg -> $HOME/Photo/2013/10/2013-10-14_11-23-54.jpg # # Данные о дате снимка ищутся в следующем порядке: # 1) Exif данные (Exif.Photo.DateTimeOriginal и Exif.Image.DateTime) # 2) В названии фотографии. Распознает различные варианты написания даты # 3) Из даты создания файла # # При запуске без аргументов обрабатывает текущий каталог и все его подкаталоги. В качестве аргумента # можно указать другой рабочий каталог-источник. # НЕ удаляет оригиналы изображений! # НЕ увеличивает разрешение # Для работы необходим пакет exiv2 (sudo apt-get install exiv2) ################################## src_dir=${1-`pwd`} # По умолчанию используется текущий каталог dst_dir=$HOME/PHOTO # Каталог в который будут скопированны обработанные фотографии quality=95 # Качество JPG изображения # resize=1600x900 # Размер после конвертации - раскомментируйте эту строку, и закомментируйте строку ниже, если хотите задать размеры изображения resize=100% # оставляем 100%-ный размер mkdir -p "$src_dir/../$(basename $src_dir)_done" # создаем папку, рядом с обрабатываемой, в которую поместим резервную копию изображения # Ищем JPG файлы в указанной папке и всех подпапках! find "$src_dir" -iname "*.jpg" | sort | while IFS= read -r file ; do # Пробуем взять дату из Exif.Photo.DateTimeOriginal или Exif.Image.DateTime for photo_date in "Exif.Photo.DateTimeOriginal" "Exif.Image.DateTime" ; do photo_date=$(exiv2 -g "$photo_date" -Pv "$file") if [ -n "$photo_date" ] ; then # Если дата найдена, прекращаем перебор break fi done if [ -z "$photo_date" ] ; then # Если в exif дата не найдена ищем в названии файла # Ищем дату в названии файла и приводим её к виду ггггммддччммсс photo_date=$(basename "$file" ".jpg" | egrep -o -m1 [0-9]\{4\}\([-_:\ ]?[0-9]\)\{10\}) if [ -n "$photo_date" ] ; then # Приводим дату к виду гггг:мм:дд чч:мм:сс для корректного добавляения в exif photo_date=$(echo "$photo_date" | tr -d "\_\-\:\ " | sed 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)/\1:\2:\3 \4:\5:/') # Добавляем дату из названия файла в exif exiv2 -M"add Exif.Image.DateTime Ascii "$photo_date"" "$file" else # Если даты в названии не нашли, берем дату изменения (создания) файла photo_date=$(date +"%Y:%m:%d %T" -r "$file") #exiv2 -M"add Exif.Image.DateTime Ascii $photo_date" "$file" fi fi # Приводим различные вариации даты к единому виду гггг мм дд чч мм сс photo_date=$(echo "$photo_date" | egrep -o -m1 [0-9]\{4\}\([-_:\ ]?[0-9]\)\{10\} | tr -d "\_\-\:\ " | sed 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)/\1 \2 \3 \4 \5 /') # Разбиваем полученную дату (гггг мм дд чч мм сс) на фрагменты # $1 - Год, $2 - Месяц, $3 - День, $4 - Час, $5 - Минута, $6 - Секунда set -- $photo_date mkdir -p "$dst_dir/$1/$1-$2-$3" # Создаем структуру папок гггг/ггг-мм-дд # Копируем фотографию, только если исходный файл новее существующего или отсутствует. При копировании сохраняется дата создания фотографии #cp -uvp "$file" "$dst_dir/$1/$2/$1-$2-$3_$4-$5-$6.jpg" # Изменяем качество и размер фотографий, переименовываем и копируем в папку назначения # convert -quality "$quality" -resize "$resize"\> -verbose "$file" "$dst_dir/$1/$2/$1-$2-$3_$4-$5-$6.jpg" convert -quality "$quality" -resize "$resize"\> -verbose "$file" "$dst_dir/$1/$1-$2-$3/$(basename $file)" # Устанавливаем дату создания файла такую же как и дата в exif # touch -t "$1$2$3$4$5.$6" "$dst_dir/$1/$2/$1-$2-$3_$4-$5-$6.jpg" touch -t "$1$2$3$4$5.$6" "$dst_dir/$1/$1-$2-$3/$(basename $file)" mv $file $src_dir/../$(basename $src_dir)_done/$(basename $file) done exit 0
Самое главное, чтобы у вашего фото-устройства была корректно задана дата :)
Для запуска скрипта, переходим в папку, в которой лежат ваши фотографии и запускаем скрипт:
sh /path-to-script.sh
Для того чтобы посмотреть полный набор exif-данных, можно воспользоваться инструментом exiftool:
exiftool image-path
Для установки данного инструмента, необходимо выполнить команду:
sudo apt install libimage-exiftool-perl
Update 2025-02-16. Обновление и оптимизация скрипта
Прошло уже много лет, как я пользуюсь этим скриптом для разброса всех своих фотографий. Многое в срипте уже изменилось, долго пользовался 2-мя скриптами - отдельно для фото и отдельно для видео. Сегодня вот решил объединить их и переписать код в более читабельный формат:
#!/bin/bash src_dir=${1-`pwd`} dst_dir="$HOME/PHOTO" backup_dir="${src_dir}/../$(basename "$src_dir")_done" mkdir -p "$backup_dir" # Функция для получения даты из EXIF-метаданных get_exif_date() { local file=$1 for photo_date in "Exif.Photo.DateTimeOriginal" "Exif.Image.DateTime"; do photo_date=$(exiv2 -g "$photo_date" -Pv "$file" 2>/dev/null) if [ -n "$photo_date" ]; then echo "$photo_date" | sed 's/ /:/' # Преобразуем пробел в двоеточие для единого формата return fi done echo "" } # Функция для получения даты из имени файла get_date_from_filename() { local file=$1 local filename=$(basename "$file") echo "$filename" | grep -oE "[0-9]{4}([0-9]{2}){2}([0-9]{2}){3}" | sed 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)/\1:\2:\3 \4:\5:/' } # Функция для получения даты создания файла get_file_creation_date() { local file=$1 if [[ "$OSTYPE" == "darwin"* ]]; then stat -f %SB -t "%Y:%m:%d %H:%M:%S" "$file" else stat -c %y "$file" | awk '{print $1, $2}' | sed 's/\.000000000//' fi } # Функция для получения даты из видеофайла get_video_date() { local file=$1 local shoot_date=$(ffprobe -v quiet -select_streams v:0 -show_entries stream_tags=creation_time -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null) if [ -n "$shoot_date" ]; then echo "$shoot_date" | sed 's/T/ /' | sed 's/\..*//' # Преобразуем формат ISO 8601 (2024-04-06T09:31:07.000000Z) в YYYY:MM:DD HH:MM:SS else local mastered_date=$(mediainfo --fullscan "$file" 2>/dev/null | grep "Mastered date" | awk -F ": " '{print $2}') if [ -n "$mastered_date" ]; then echo "$mastered_date" else echo "" fi fi } # Функция для получения даты файла get_date() { local file=$1 local type=$2 if [ "$type" == "photo" ]; then local exif_date=$(get_exif_date "$file") if [ -n "$exif_date" ]; then echo "$exif_date" return fi fi local filename_date=$(get_date_from_filename "$file") if [ -n "$filename_date" ]; then echo "$filename_date" return fi if [ "$type" == "video" ]; then local video_date=$(get_video_date "$file") if [ -n "$video_date" ]; then echo "$video_date" return fi fi local file_date=$(get_file_creation_date "$file") if [ -n "$file_date" ]; then echo "$file_date" return fi date +"%Y:%m:%d %H:%M:%S" } # Функция для перемещения файла move_file() { local file=$1 local date=$2 local type=$3 # Преобразуем дату в формат YYYY:MM:DD local year=$(echo "$date" | awk -F "[: -]" '{print $1}') # Разделители: двоеточие, пробел, дефис local month=$(echo "$date" | awk -F "[: -]" '{print $2}') local day=$(echo "$date" | awk -F "[: -]" '{print $3}') # Создаем директорию назначения local dst_path="$dst_dir/$year/$year-$month-$day" mkdir -p "$dst_path" echo "Перемещение файла '$file' в '$dst_path/$(basename "$file")'..." # Перемещение файла с перезаписью mv -f "$file" "$dst_path/$(basename "$file")" # Создаем резервную копию cp -p "$dst_path/$(basename "$file")" "$backup_dir/" echo "Файл '$file' успешно перемещен в '$dst_path'." } # Обработка фотографий find "$src_dir" -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" | sort | while IFS= read -r file; do photo_date=$(get_date "$file" "photo") move_file "$file" "$photo_date" "photo" done # Обработка видео find "$src_dir" -type f \( -iname "*.mp4" -o -iname "*.avi" -o -iname "*.mkv" -o -iname "*.mov" -o -iname "*.wmv" -o -iname "*.3gp" -o -iname "*.flv" -o -iname "*.webm" -o -iname "*.mpeg" -o -iname "*.mpg" \) | sort | while IFS= read -r file; do video_date=$(get_date "$file" "video") move_file "$file" "$video_date" "video" done exit 0
Скрипт проверен на MacOs, на других linux-подобных системах может потребоваться доработка
Разработка сайта
Подайте заявку на разработку сайта на базе готового решения от компании 1С-Битрикс или одного из партнеров компании. Максимально подробно опишите, чему будет посвящен сайт, если это интернет-магазин - что он будет продавать, нужна ли мультиязычность, будут ли разные типы цен (розница, опт, крупный опт), будет ли интеграция с 1С, будет ли выгрузка товаров на различные торговые площадки...
Сопровождение сайта
Вы можете подать заявку на сопровождение вашего сайта на базе 1С-Битрикс. Сопровождение включает в себя: проверка актуальности обновлений сайта, проверка актуальности резервной копии, консультации по сайту. Опишите в заявке, какие еще объемы планируются на сопровождении и на какой срок вы планируете заключить договор на сопровождение - мы подберем подходящий вам бюджет на сопровождение
Работы по сайту
Вы можете подать заявку на выполнение определенного объема работ по сайту. Опишите в заявке объем работ. Это может быть разработка какого-то нового функционала, доработки по имеющемуся функционалу, доработки под требования сео-специалистов. На основании заявки вам будет сформирован бюджет работ, а также названы сроки на выполнение тех или иных работ.