Универсальный bash‑скрипт для безопасного уменьшения изображений (с бэкапом и сохранением имён)

Универсальный bash‑скрипт для безопасного уменьшения изображений (с бэкапом и сохранением имён)
12 сентября 2025
4 мин.
357
1
28 сентября 2025

готовый скрипт, который рекурсивно проходит по каталогу, уменьшает большие изображения до заданного порога, делает бэкап только изменённых файлов, сохраняет исходные имена, поддерживает dry‑run и выбор форматов. Идеален для рабочих директорий upload/ в Bitrix/WordPress и массивов контент‑фото.

это готовый скрипт, который рекурсивно проходит по каталогу, уменьшает большие изображения до заданного порога, делает бэкап только изменённых файлов, сохраняет исходные имена, поддерживает dry‑run и выбор форматов. Идеален для рабочих директорий upload/ в Bitrix/WordPress и массивов контент‑фото.

Зачем это нужно

  • Нет падений PHP из‑за «переростков»: уменьшенные фото меньше нагружают GD/Imagick и не выбивают memory_limit.
  • Экономия диска и трафика: меньше мегабайт → быстрее страницы, ниже нагрузка на CDN/сервер.
  • Безопасно: перед изменением скрипт положит оригинал в каталог бэкапа с сохранением структуры → всегда можно откатиться.
  • Просто: один файл, без зависимостей кроме ImageMagick.

Что требуется

  • Linux/macOS (bash).
  • Пакет ImageMagick:
    • Ubuntu/Debian: sudo apt install imagemagick
    • CentOS/RHEL/Rocky/Alma: sudo yum install ImageMagick
    • Проверка: identify -version или magick -version.

Что умеет скрипт

  • Рекурсивно обходит указанный каталог, игнорируя папку бэкапа.
  • Уменьшает пропорционально, чтобы длинная сторона ≤ MAX (по умолчанию 2000 px). Маленькие файлы не трогает.
  • Перед изменением копирует оригинал в backup_YYYYmmdd_HHMMSS/… с сохранением дерева подпапок.
  • Сохраняет имена файлов (перезаписывает уменьшенной версией).
  • Поддерживает dry‑run (прогон без изменений) и выбор расширений.

По умолчанию обрабатываются: jpg,jpeg,png. Можно добавить gif (не рек. для анимированных) или другие.

Код скрипта img-shrink-backup.sh

#!/usr/bin/env bash


# ---------- проверка ImageMagick ----------
# Поддерживаем два интерфейса: identify/mogrify или magick identify|mogrify
ID_CMD=(identify)
MG_CMD=(mogrify)
if ! command -v "${ID_CMD[0]}" >/dev/null || ! command -v "${MG_CMD[0]}" >/dev/null; then
if command -v magick >/dev/null; then
ID_CMD=(magick identify)
MG_CMD=(magick mogrify)
else
echo "Ошибка: ImageMagick не найден. Установите пакет (identify/mogrify или 'magick')." >&2
exit 1
fi
}


# ---------- подготовка ----------
DIR="${DIR%/}"
if [[ -z "$BACKUP_DIR" ]]; then
TS="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="$DIR/backup_${TS}"
fi
mkdir -p "$BACKUP_DIR"


IFS=',' read -r -a EXTS <<< "$EXT_LIST"
FIND_EXPR=()
for ext in "${EXTS[@]}"; do
FIND_EXPR+=( -iname "*.${ext}" -o )
done
unset 'FIND_EXPR[${#FIND_EXPR[@]}-1]' 2>/dev/null || true


echo "Каталог: $DIR"
echo "Порог: ${MAX}px по длинной стороне"
echo "Расширения: ${EXT_LIST}"
echo "Бэкап в: $BACKUP_DIR"
[[ "$DRYRUN" -eq 1 ]] && echo "Режим: DRY-RUN (без изменений)"


COUNT_TOTAL=0
COUNT_RESIZED=0


while IFS= read -r -d '' FILE; do
(( COUNT_TOTAL++ )) || true


if ! DIM="$(${ID_CMD[@]} -format '%w %h' -- "$FILE" 2>/dev/null)"; then
echo "Пропуск (не удалось определить размер): ${FILE#$DIR/}" >&2
continue
fi
WIDTH=${DIM%% *}
HEIGHT=${DIM##* }


if (( WIDTH > MAX || HEIGHT > MAX )); then
REL="${FILE#$DIR/}"
BFILE="$BACKUP_DIR/$REL"


if [[ "$DRYRUN" -eq 1 ]]; then
echo "[DRY] ${REL} (${WIDTH}x${HEIGHT} -> <= ${MAX})"
continue
fi


mkdir -p -- "$(dirname -- "$BFILE")"
cp -p -- "$FILE" "$BFILE"


${MG_CMD[@]} -resize "${MAX}x${MAX}>" -- "$FILE"


NEW_DIM="$(${ID_CMD[@]} -format '%w %h' -- "$FILE" 2>/dev/null || echo "")"
echo "[OK ] ${REL} (${WIDTH}x${HEIGHT} -> ${NEW_DIM})"
(( COUNT_RESIZED++ )) || true
else
echo "[=] ${FILE#$DIR/} (${WIDTH}x${HEIGHT}, <= ${MAX})"
fi


done < <( find "$DIR" -type d -path "$BACKUP_DIR" -prune -o -type f \( "${FIND_EXPR[@]}" \) -print0 )


echo "Готово. Обработано файлов: $COUNT_TOTAL; уменьшено: $COUNT_RESIZED"

⚠️ По умолчанию скрипт не трогает EXIF/метаданные и не меняет качество JPEG. Это безопасно. В конце статьи есть раздел «Доп. опции», где показано, как добавить -strip и -quality при необходимости.

Установка и запуск

  1. Сохраните файл:
    nano img-shrink-backup.sh # вставьте код выше
    chmod +x img-shrink-backup.sh
  2. Пробный запуск (ничего не меняет):
    ./img-shrink-backup.sh -n /var/www/your-site/upload
  3. Реальная обработка с настройками по умолчанию (2000 px):
    ./img-shrink-backup.sh /var/www/your-site/upload

Примеры использования

  1. Изменить порог до 2400 px:
    ./img-shrink-backup.sh -m 2400 /data/images
  2. Добавить форматы (например, ещё и GIF):
    ./img-shrink-backup.sh -e jpg,jpeg,png,gif /data/pics
  3. Сохранить бэкап в конкретное место:
    ./img-shrink-backup.sh -b /var/backups/images_$(date +%F) /var/www/site/upload
  4. Получить абсолютный путь к текущей папке и запустить:
    ./img-shrink-backup.sh "$(pwd)"

Как восстановить файлы из бэкапа

Все оригиналы лежат в каталоге backup_YYYYmmdd_HHMMSS (или вашем -b).

  • Восстановить один файл:
    cp -p backup_20250101_120000/path/to/image.jpg path/to/image.jpg
  • Восстановить всё дерево:
    rsync -a backup_20250101_120000/ ./

Советы и частые вопросы

  • Сохраняются ли имена файлов? Да, меняется только содержимое — имя остаётся.
  • Что с качеством и EXIF? По умолчанию не трогаем. Если нужно сильнее ужать JPEG, добавьте к строке с mogrify опции -strip -quality 82:
    ${MG_CMD[@]} -strip -quality 82 -resize "${MAX}x${MAX}>" -- "$FILE"
  • Анимированные GIF? Скрипт уменьшит первый кадр у некоторых сборок ImageMagick или попытается перерасчитать все кадры — это дорого. Лучше исключить большие GIF или обрабатывать их отдельно.
  • HEIC/WEBP? Если в вашей сборке ImageMagick включена поддержка — можно добавить расширения в -e. Для HEIC иногда требуется пакет libheif.
  • CMYK‑JPEG из типографий? Могут выглядеть «тускло» в вебе. Скрипт их не переколорит. При необходимости добавляйте профили вручную (-colorspace sRGB).
  • Можно быстрее? Для больших массивов файлов используйте GNU parallel или запускайте скрипт по расписанию через cron. Также помогает выполнение на SSD и локальном диске.

Интеграция в рабочий процесс

  • Перед импортами (1С, парсеры, контент‑миграции) прогоняйте папку входящих изображений.
  • После загрузки контент‑менеджерами — крон‑задача раз в час/ночь.
  • Перед сборкой статики/CDN‑инвалидацией — как часть CI/CD шага.

Пример cron (ежедневно в 02:30):

30 2 * * * /opt/tools/img-shrink-backup.sh -m 2000 -e jpg,jpeg,png /var/www/site/upload >> /var/log/img-shrink.log 2>&1

Чем это полезно бизнесу и разработчикам

  • Стабильность: меньше рисков упасть из‑за памяти при генерации ресайзов/WEBP.
  • Производительность: ускорение LCP/CLS, рост Core Web Vitals.
  • Экономия: меньше места и трафика → ниже счета за хостинг/CDN.
  • Контроль: бэкап на каждый изменённый файл, прозрачные логи и лёгкий откат.

Доп. опции (по желанию)

  • Жёстче сжимать JPEG: -quality 80..85.
  • Убирать метаданные: -strip.
  • Принудительно переводить в sRGB: -colorspace sRGB.
  • Исключить отдельные подпапки: добавьте условия к find.