Заметки программиста

Синхронизация каталогов

Для автоматической синхронизации каталогов терминале Ubuntu лучше всего использовать утилиту rsync. Это стандартный, быстрый и безопасный инструмент.

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

Используйте код с осторожностью!

Шаг 1. Безопасная проверка (Dry Run)

Всегда сначала запускайте симуляцию, чтобы увидеть, какие файлы будут скопированы или удалены, без внесения реальных изменений:

rsync -avun --delete /путь/к/папке1/ /путь/к/папке2/
  • -a — архивный режим (сохраняет права доступа, ссылки, даты изменения).
  • -v — подробный вывод (покажет список файлов).
  • -u — обновлять только измененные файлы (пропускать те, что новее в приемнике).
  • -ndry run (симуляция, ничего не записывает).
  • --delete — удаляет в папке2 файлы, которых больше нет в папке1 (сделайте копию, если боитесь потерять данные).
  • Важно: Слэши / в конце путей обязательны, иначе rsync создаст папку внутри папки.

Шаг 2. Реальная синхронизация

Если список файлов в симуляции вас устраивает, уберите флаг -n для выполнения синхронизации:

rsync -avu --delete /путь/к/папке1/ /путь/к/папке2/

Шаг 3. Автоматизация по расписанию (Cron)

Чтобы синхронизация выполнялась сама (например, каждый час или каждый день), добавьте команду в планировщик cron.

  1. Откройте редактор задач: bashcrontab -e
  2. Добавьте строку в самый конец файла.
  • Пример (каждый день в 00:00): 0 0 * * * rsync -au --delete /путь/к/папке1/ /путь/к/папке2/
  • Пример (каждый час): 0 * * * * rsync -au --delete /путь/к/папке1/ /путь/к/папке2/
  1. Сохраните и закройте файл (в nano: Ctrl+O, Enter, Ctrl+X).

Как сделать двустороннюю синхронизацию (чтобы изменения из папки 2 тоже шли в папку 1)?

Для полноценной двусторонней (бидирекционной) синхронизации стандартный rsync не подходит. Он умеет копировать данные только в одну сторону, и если запустить его сначала в одну сторону, а потом в другую, он может затереть более новые файлы.

Для решения этой задачи в терминале Ubuntu используются специализированные инструменты.

Вариант 1: Unison (Самый надежный и популярный инструмент)

Unison — это утилита, созданная специально для двусторонней синхронизации. Она отслеживает изменения в обеих папках, понимает, где файл обновился, и безопасно переносит изменения. Если один и тот же файл изменился в обеих папках одновременно, Unison не затрет его, а сообщит о конфликте.

1. Установка

sudo apt update && sudo apt install unison

2. Первый (безопасный) запуск в текстовом режиме

Запустите команду в интерактивном режиме. При первом запуске утилита построит базу данных и может задать вопросы по файлам:

unison -batch /путь/к/папке1 /путь/к/папке2
  • Флаг -batch автоматически принимает очевидные решения (например, если файл появился только в одной папке, он скопирует его во вторую).
  • Если возникнет конфликт (файл изменен и там, и там), Unison пропустит его, чтобы вы не потеряли данные.

3. Настройка автоматизации

Чтобы синхронизация происходила полностью автоматически без лишних вопросов, используйте флаг -auto:

unison -auto -batch /путь/к/папке1 /путь/к/папке2

Вариант 2: osync — скрипт на базе rsync

Если вы хотите использовать именно возможности rsync, существует мощный bash-скрипт osync, который добавляет ему двустороннюю логику и контроль конфликтов.

1. Установка

sudo apt install osync

2. Запуск синхронизации

osync.sh --master="/путь/к/папке1" --slave="/путь/к/папке2"
  • Скрипт создаст резервные копии на случай конфликтов и аккуратно объединит содержимое папок.

Как автоматизировать двустороннюю синхронизацию

Как и в случае с обычным rsync, вы можете добавить команду Unison в планировщик задач cron.

  1. Откройте планировщик: crontab -e
  2. Добавьте задачу (например, синхронизация каждые 30 минут): */30 * * * * unison -auto -batch /путь/к/папке1 /путь/к/папке2

Чтобы заставить Unison игнорировать определенные файлы или папки, используются специальные правила исключений с помощью параметра -ignore.

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

Способ 1. Через командную строку (для разовых запусков)

Вы можете добавить один или несколько флагов -ignore непосредственно в команду синхронизации.

Синтаксис флага: -ignore "Modifier Шаблон"

  • Name — совпадение по имени файла или папки (в любом месте дерева).
  • Path — точный путь относительно корня синхронизации.

Пример команды:

unison -auto -batch -ignore "Name .git" -ignore "Name node_modules" -ignore "Name .Trash*" /путь/к/папке1 /путь/к/папке2

Способ 2. Через файл конфигурации (рекомендуемый для автоматизации)

Если вы запускаете Unison через cron или часто используете его вручную, удобнее создать именованный профиль. В нем можно прописать все настройки и исключения один раз.

  1. Создайте файл профиля (например, с именем mysync.prf) в домашней директории настроек Unison: mkdir -p ~/.unison nano ~/.unison/mysync.prf
  2. Вставьте в файл следующие настройки:
    # Пути к синхронизируемым папкам
    root = /путь/к/папке1
    root = /путь/к/папке2
    
    # Автоматический режим (эквивалент флагов -auto -batch)
    auto = true
    batch = true
    
    # Список игнорируемых файлов и папок
    ignore = Name .git
    ignore = Name node_modules
    ignore = Name .Trash*
    ignore = Name *~
    ignore = Name .DS_Store
    ignore = Name *.tmp
    
  3. Запустите синхронизацию одной короткой командой, указав имя профиля: unison mysync

Теперь в планировщик cron вместо длинной строки с путями достаточно будет добавить лаконичную команду: */30 * * * * unison mysync.


Чтобы при возникновении конфликтов всегда побеждала определенная папка (например, Папка 1), в Unison используется параметр force.

Когда этот параметр активен, Unison при любых несовпадениях или конфликтах изменений просто перезаписывает данные во второй папке копиями из первой.

Вы можете настроить это как в команде, так и в файле профиля.

Способ 1. Через командную строку

Добавьте флаг -force и укажите в нем путь к главной папке.

Важно: Путь в параметре -force должен абсолютно точно (символ в символ) совпадать с одним из двух путей, указанных в конце команды.

unison -auto -batch -force /путь/к/папке1 /путь/к/папке1 /путь/к/папке2

В данном примере /путь/к/папке1 указан дважды: первый раз для флага -force, второй раз как корень синхронизации.

Способ 2. Через файл конфигурации (профиль)

Если вы используете файл профиля (~/.unison/mysync.prf), добавьте в него строку force = /путь/к/папке1.

Ваш файл конфигурации будет выглядеть так:

root = /путь/к/папке1
root = /путь/к/папке2

# При конфликтах всегда берем файлы из папки1
force = /путь/к/папке1

auto = true
batch = true

ignore = Name .git
ignore = Name node_modules

Альтернатива: Более мягкий режим (prefer)

Если режим force кажется вам слишком агрессивным (так как он принудительно заменяет даже те файлы, которые в Папке 2 новее), можно использовать параметр prefer:

prefer = /путь/к/папке1
  • Как это работает: Если файл изменился только в Папке 2, он мирно скопируется в Папку 1. Но если один и тот же файл был изменен одновременно в обеих папках, Unison не выдаст ошибку конфликта, а молча возьмет версию из Папки 1.

Добавление настроек бэкапа

Откройте ваш файл профиля (например, nano ~/.unison/mysync.prf) и добавьте в него следующие строки:

# Включаем создание резервных копий
backup = Name *

# Указываем, где хранить бэкапы (они будут лежать внутри синхронизируемых папок)
backuplocation = local

# Название папки для бэкапов внутри каждого каталога
backupprefix = .unison-backups/

# Сколько предыдущих версий одного и того же файла хранить
maxbackups = 3

Как это работает на практике

  • backup = Name * означает, что бэкап будет делаться для всех файлов без исключения.
  • Внутри ваших папок появится скрытая директория .unison-backups.
  • Если Unison заменяет файл script.sh, его старая версия переместится в .unison-backups/script.sh.0.bak (или с другим порядковым номером).
  • Параметр maxbackups = 3 гарантирует, что история изменений файла не будет раздувать диск бесконечно — будут храниться только последние 3 версии.

Вариант для запуска через командную строку (без профиля)

Если вы запускаете утилиту одной командой, то аргументы будут выглядеть громоздко, но логика останется той же:

unison -auto -batch -backup "Name *" -backuplocation local -backupprefix ".unison-backups/" -maxbackups 3 /путь/к/папке1 /путь/к/папке2

Важно: Поскольку папка .unison-backups/ будет создаваться внутри самих синхронизируемых каталогов, Unison автоматически исключит её из процесса зеркалирования, чтобы не гонять копии бэкапов по кругу.


Чтобы перенести бэкапы в одну централизованную папку вне рабочих каталогов, нужно изменить параметр backuplocation на значение central, а также указать путь к этой папке через параметр backupdir.

Вот как это правильно настроить.

Шаг 1. Создайте общую папку для бэкапов

Перед запуском синхронизации обязательно создайте этот каталог на диске (замените user на ваше реальное имя пользователя в Ubuntu):

mkdir -p /home/user/unison_archive

Шаг 2. Настройка файла профиля

Откройте ваш конфигурационный файл ~/.unison/mysync.prf и замените прошлые настройки бэкапа на следующие:

# Включаем создание резервных копий для всех файлов
backup = Name *

# Указываем хранить бэкапы в единой центральной папке
backuplocation = central
backupdir = /home/user/unison_archive

# Оставляем префикс (к именам файлов будет добавляться расширение .bak)
backupprefix = .bak.

# Сколько предыдущих версий одного и того же файла хранить
maxbackups = 3

Как теперь будут храниться бэкапы?

Unison воссоздаст структуру подкаталогов внутри вашей общей папки.

Например, если в вашей рабочей папке изменился файл documents/report.txt, то его резервная копия сохранится по пути:
/home/user/unison_archive/documents/report.txt.0.bak


Вариант для командной строки (без файла профиля)

Если вы предпочитаете запускать утилиту вручную без использования .prf файлов, команда со всеми флагами будет выглядеть так:

unison -auto -batch -backup "Name *" -backuplocation central -backupdir "/home/user/unison_archive" -backupprefix ".bak." -maxbackups 3 /путь/к/папке1 /путь/к/папке2

Для автоматической очистки старых бэкапов в Ubuntu идеально подходит стандартная команда find. Она умеет искать файлы по времени их последнего изменения и сразу удалять их.

Шаг 1. Команда для проверки (безопасный запуск)

Перед тем как что-то удалять, всегда полезно посмотреть список файлов, которые подходят под условия. Запустите эту команду в терминале (замените user на ваше имя пользователя):

find /home/user/unison_archive/ -type f -mtime +30
  • -type f — искать только файлы (не трогая структуру папок).
  • -mtime +30 — искать файлы, которые были изменены более 30 дней назад.

Шаг 2. Команда для удаления

Если список файлов правильный, добавьте в конец флаг -delete:

find /home/user/unison_archive/ -type f -mtime +30 -delete

Также полезно сразу удалять пустые папки, которые остаются после удаления файлов, чтобы архив не засорялся:

find /home/user/unison_archive/ -type d -empty -delete

Шаг 3. Автоматизация процесса (добавление в Cron)

Чтобы очистка происходила сама (например, раз в сутки ночью), объедините эти две команды и добавьте их в планировщик задач.

  1. Откройте планировщик: crontab -e
  2. Добавьте в самый конец файла следующую строку (задача будет запускаться каждый день в 02:00 ночи): 0 2 * * * find /home/user/unison_archive/ -type f -mtime +30 -delete && find /home/user/unison_archive/ -type d -empty -delete
  3. Сохраните и закройте файл.

теперь ваша система полностью автономна: Unison делает синхронизацию и складывает бэкапы в общую папку, а Cron каждую ночь следит, чтобы этот архив не разрастался больше чем за последние 30 дней.


Чтобы история удалений записывалась в лог-файл, команду find нужно немного изменить. Флаг -delete удаляет файлы молча, поэтому вместо него мы будем использовать флаг -exec для удаления с выводом имени файла, а также добавим запись даты.

Вот готовое решение:

Шаг 1. Команда для терминала (и для Cron)

Вместо флага -delete используйте следующую конструкцию:

find /home/user/unison_archive/ -type f -mtime +30 -exec sh -c 'echo "$(date "+%Y-%m-%d %H:%M:%S") | Deleted file: $1"; rm "$1"' _ {} \; >> /home/user/unison_archive_cleanup.log

Как это работает:

  • -exec sh -c '...' _ {} \; — запускает мини-скрипт для каждого найденного файла. Переменная {} заменяется на путь к файлу.
  • echo "$(date ...) | Deleted file: $1" — формирует строку с текущей датой, временем и именем удаляемого файла.
  • rm "$1" — удаляет сам файл.
  • >> /home/user/unison_archive_cleanup.log — дописывает (аппендирует) этот вывод в файл лога в вашей домашней папке.

Шаг 2. Обновление задачи в Cron

Чтобы автоматизировать этот процесс, откройте планировщик через crontab -e и замените старую команду очистки на новую:

text

0 2 * * * find /home/user/unison_archive/ -type f -mtime +30 -exec sh -c 'echo "$(date "+\%Y-\%m-\%d \%H:\%M:\%S") | Deleted file: $1"; rm "$1"' _ {} \; >> /home/user/unison_archive_cleanup.log && find /home/user/unison_archive/ -type d -empty -delete
  • Важно для Cron: Внутри crontab знаки процента % имеют спецсимвольное значение, поэтому их нужно обязательно экранировать обратным слэшем (\%Y-\%m-\%d). В обычной консоли это делать не нужно.
  • Вторая часть команды (&& find ... -type d -empty -delete) по-прежнему будет тихо удалять оставшиеся пустые папки.

Как будет выглядеть лог-файл?

Если вы откроете файл cat /home/user/unison_archive_cleanup.log, вы увидите аккуратные записи:

2026-06-17 02:00:01 | Deleted file: /home/user/unison_archive/documents/report.txt.2.bak
2026-06-17 02:00:02 | Deleted file: /home/user/unison_archive/photo.jpg.0.bak