Русский flag Русский

Safe Find & Replace: How Not to Break Binaries

Published on 2025-12-30

When working on real projects (CDN change, migration, refactor) you often need to bulk-replace one URL with another.

At first glance the task seems trivial: sed -i 's|old|new|g' **/* — and done.

In reality that approach is Russian roulette.

A careless replacement leads to:

  • 💀 Corruption of binary files (images, pdf, archives);
  • 📉 Garbage in git history (binaries marked as changed);
  • 🚫 Inability to cleanly roll back if a backup wasn’t made.

In this note we’ll cover a production-grade algorithm: change only text, don’t touch binaries, make a targeted backup.

Input data

  • Old URL: https://static-old.example-cdn.net
  • New URL: https://cdn-new.example-storage.net
  • Context: Project with mixed content (HTML, JS, YAML + PNG, JPG, WOFF2).

🛠 Steps

1. Preparation and search (Dry Run)

The key tool is grep -I (ignores binary files, even if bytes in them match the string).

First, just see what we’re going to change:

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

Important: make sure the list contains only text files (no images, fonts, etc.). If everything looks reasonable — proceed.

2. Create a “smart” backup

Don’t copy the whole project — that’s slow and takes space. Save only the files that contain the target string, preserving hierarchy and metadata.

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/{}"'

Now backup_before_replace contains an exact copy of only the files to be changed. Rollback is a simple copy back.

3. Perform the replacement (Safe Replace)

sed -i behaves differently on Linux (GNU) and macOS (BSD):

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

To make the script work everywhere (locally, in CI, on Mac/Linux), use perl — it’s identical across *nix systems.

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 and \E automatically escape all special characters in the URL (dots, slashes, dashes) — no need to escape manually.

4. Verify the result (Verification)

Make sure everything went well:

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

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

Additionally, you can run git status or git diff --stat to see the actual changes.

💡 Why this is correct

  1. grep -I — reliable protection against damaging binaries.
  2. Targeted backup — save only the delta, save space and time.
  3. perl instead of sed — cross-platform stability (Linux, macOS, CI).
  4. Variables and clear steps — the script is easy to read and adapt.

TL;DR — Ready-to-use snippet for “right now”

Paste into the terminal and replace your URLs:

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/. ."

This approach is production-proven — safe, reliable, and universal. Good luck with your migrations! 🚀

Related reviews

Huge thanks to Mikhail — I contacted him about a very urgent server setup issue because I'm not strong in that area and needed to show the site to a client. Quick response, no-nonsense help, and very fast! Wishing you many orders and a better rating. Thank you so much!

Ekleo

Ekleo · VPS setup, server setup

A very powerful buyer

2025-11-28 · ⭐ 5/5

Many thanks to Mikhail — I reached out to him with a very urgent issue regarding server configuration, since I'm not very skilled in this myself and needed to show the site to the client. Quick response, help without unnecessary words and very fast! I wish you many orders and a better rating! Thank you so much!

Need help?

Get in touch with me and I'll help solve the problem

Related Posts