Флаг: English English

Безопасный Find & Replace: как не убить бинарники

Опубликовано 30.12.2025

При работе с реальными проектами (смена CDN, миграция, рефакторинг) часто нужно массово заменить один URL на другой.

На первый взгляд задача кажется тривиальной: sed -i 's|old|new|g' **/* — и готово.

В реальности такой подход — это русская рулетка.

Неосторожная замена приводит к:

  • 💀 Повреждению бинарных файлов (images, pdf, archives);
  • 📉 Мусору в git-истории (бинарники помечаются как изменённые);
  • 🚫 Невозможности чистого отката, если бэкап не был сделан.

В этой заметке разберём production-grade алгоритм: меняем только текст, не трогаем бинарники, делаем точечный бэкап.

Вводные данные

  • Старый URL: https://static-old.example-cdn.net
  • Новый URL: https://cdn-new.example-storage.net
  • Контекст: Проект со смешанным контентом (HTML, JS, YAML + PNG, JPG, WOFF2).

🛠 Алгоритм действий

1. Подготовка и поиск (Dry Run)

Ключевой инструмент — grep -I (игнорирует бинарные файлы, даже если в них байты совпадают со строкой).

Сначала просто посмотрим, что мы собираемся менять:

# Ищем рекурсивно, игнорируем бинарники, выводим список файлов
grep -rIl 'https://static-old.example-cdn.net' .

Важно: убедитесь, что в списке только текстовые файлы (нет картинок, шрифтов и т.п.). Если всё выглядит адекватно — идём дальше.

2. Создаём “умный” бэкап

Не копируем весь проект — это долго и занимает место. Сохраняем только те файлы, которые содержат искомую строку, с сохранением иерархии и метаданных.

SEARCH="https://static-old.example-cdn.net"
BACKUP_DIR="backup_before_replace"

mkdir -p "$BACKUP_DIR"

# Копируем только файлы с совпадением
find . -type f -print0 \
  | xargs -0 grep -Il "$SEARCH" \
  | xargs -I{} sh -c 'mkdir -p "$BACKUP_DIR/$(dirname "{}")" && cp -p "{}" "$BACKUP_DIR/{}"'

Теперь в backup_before_replace лежит точная копия только изменяемых файлов. Откат — простое копирование обратно.

3. Выполняем замену (Safe Replace)

sed -i работает по-разному на Linux (GNU) и macOS (BSD):

  • Linux: sed -i 's/old/new/g'
  • macOS: sed -i '' 's/old/new/g'

Чтобы скрипт работал везде (локально, в CI, на Mac/Linux), используем perl — он идентичен на всех *nix-системах.

OLD="https://static-old.example-cdn.net"
NEW="https://cdn-new.example-storage.net"

find . -type f -not -path "./$BACKUP_DIR/*" -print0 \
  | xargs -0 grep -Il "$OLD" \
  | xargs -0 perl -pi -e "s|\Q$OLD\E|$NEW|g"

\Q и \E автоматически экранируют все спецсимволы в URL (точки, слеши, дефисы) — не нужно вручную бэкслешить.

4. Контроль результата (Verification)

Убеждаемся, что всё прошло успешно:

# Должно вернуть пустой вывод
grep -rIl "$OLD" . --exclude-dir="$BACKUP_DIR"

# Должно показать изменённые файлы (пример: первые 5)
grep -rIl "$NEW" . --exclude-dir="$BACKUP_DIR" | head -n 5

Дополнительно можно выполнить git status или git diff --stat, чтобы увидеть реальные изменения.

💡 Почему это правильно

  1. grep -I — надёжная защита от повреждения бинарников.
  2. Точечный бэкап — сохраняем только дельту, экономим место и время.
  3. perl вместо sed — кросс-платформенная стабильность (Linux, macOS, CI).
  4. Переменные и чёткие шаги — скрипт легко читаем и адаптируем.

TL;DR — Готовый сниппет для «здесь и сейчас»

Вставьте в терминал и замените свои URL:

SEARCH="https://static-old.example-cdn.net"
REPLACE="https://cdn-new.example-storage.net"
BACKUP="backup_$(date +%s)"

mkdir -p "$BACKUP"

# 1. Точечный бэкап только файлов с совпадением
find . -type f -print0 \
  | xargs -0 grep -Il "$SEARCH" \
  | xargs -I{} sh -c 'mkdir -p "$BACKUP/$(dirname "{}")" && cp -p "{}" "$BACKUP/{}"'

# 2. Безопасная замена (perl — работает на Linux и macOS)
find . -type f -not -path "./$BACKUP/*" -print0 \
  | xargs -0 grep -Il "$SEARCH" \
  | xargs -0 perl -pi -e "s|\Q$SEARCH\E|$REPLACE|g"

echo "Готово! Бэкап сохранён в папке $BACKUP"
echo "Откат (если нужно): cp -r $BACKUP/. ."

Этот подход проверен в продакшене — безопасно, надёжно и универсально. Удачных миграций! 🚀

Отзывы по теме

Огромное спасибо Михаилу, обратился к нему с очень срочным вопросом по настройке сервера, так как сам в этом не очень силен а нужно сайт показать заказчику. Ответ быстрый, помощь без лишних слов и очень быстро! Желаю вам много заказов и лучшего рейтинга! Спасибо огромное!

Ekleo

Ekleo · Настройка vps, настройка сервера

Очень мощный покупатель

28.11.2025 · ⭐ 5/5

Огромное спасибо Михаилу, обратился к нему с очень срочным вопросом по настройке сервера, так как сам в этом не очень силен а нужно сайт показать заказчику. Ответ быстрый, помощь без лишних слов и очень быстро! Желаю вам много заказов и лучшего рейтинга! Спасибо огромное!

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Похожие посты