Безопасный 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, чтобы увидеть реальные изменения.
💡 Почему это правильно
grep -I— надёжная защита от повреждения бинарников.- Точечный бэкап — сохраняем только дельту, экономим место и время.
perlвместоsed— кросс-платформенная стабильность (Linux, macOS, CI).- Переменные и чёткие шаги — скрипт легко читаем и адаптируем.
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/. ."
Этот подход проверен в продакшене — безопасно, надёжно и универсально. Удачных миграций! 🚀
Отзывы по теме
Всё прошло хорошо, исполнитель быстро реагировал на вопросы и помог решить проблему. Спасибо!
visupSTUDIO · Настройка vps, настройка сервера
16.12.2025 · ⭐ 5/5
Всё прошло хорошо, исполнитель быстро реагировал на вопросы и помог решить проблему. Спасибо!
Все сделали оперативно. Будем и дальше обращаться. Рекомендую!
rotant · Настройка vps, настройка сервера
10.12.2025 · ⭐ 5/5
Все сделали оперативно. Будем и дальше обращаться. Рекомендую!
Все сделали оперативно. Михаил всегда на связи. Будем и дальше обращаться
samstiray · Настройка vps, настройка сервера
10.12.2025 · ⭐ 5/5
Все сделали оперативно. Михаил всегда на связи. Будем и дальше обращаться
Михаил, профессионал! Уже ни первый раз показал это на практике.
Vadim_U · Настройка vps, настройка сервера
Освоившийся покупатель03.12.2025 · ⭐ 5/5
Михаил, профессионал! Уже ни первый раз показал это на практике.
Огромное спасибо Михаилу, обратился к нему с очень срочным вопросом по настройке сервера, так как сам в этом не очень силен а нужно сайт показать заказчику. Ответ быстрый, помощь без лишних слов и очень быстро! Желаю вам много заказов и лучшего рейтинга! Спасибо огромное!
Ekleo · Настройка vps, настройка сервера
Очень мощный покупатель28.11.2025 · ⭐ 5/5
Огромное спасибо Михаилу, обратился к нему с очень срочным вопросом по настройке сервера, так как сам в этом не очень силен а нужно сайт показать заказчику. Ответ быстрый, помощь без лишних слов и очень быстро! Желаю вам много заказов и лучшего рейтинга! Спасибо огромное!
Спасибо, быстро помог.
Bodanov · Настройка vps, настройка сервера
Мощный покупатель28.11.2025 · ⭐ 5/5
Спасибо, быстро помог.