Автоматическая синхронизации файлов между двумя директориями в Linux
telegram https://t.me/LinuxSkillДля выполнения автоматической синхронизации файлов между двумя директориями в Linux необходимо использовать мощный и эффективный инструмент для синхронизации, такой как rsync, и затем автоматизировать его запуск с помощью планировщика заданий, например, cron или systemd.timer.
Ниже приведено максимально подробное объяснение, как реализовать этот процесс.
Шаг 1: Выбор и настройка команды синхронизации (rsync)
rsync — это эффективный инструмент, основная цель которого — синхронизировать две файловые системы, как локальные, так и удаленные. Он работает быстро и эффективно, поскольку передает только изменения в файлах (различия между версиями), а не копирует весь файл целиком.
Чтобы обеспечить полную синхронизацию (т.е. сделать целевой каталог идентичным исходному), необходимо использовать набор ключей, которые:
- Сохраняют все атрибуты файлов.
- Передают данные рекурсивно (включая подкаталоги).
- Удаляют файлы в целевой директории, если они были удалены в исходной (режим "зеркалирования").
Рекомендуемая команда rsync
Предположим, у нас есть:
- Исходный каталог (Source):
/path/to/source_dir/ - Целевой каталог (Destination):
/path/to/destination_dir/
Команда для полной синхронизации будет выглядеть так:
rsync -av --delete /path/to/source_dir/ /path/to/destination_dir/
Объяснение ключей:
-a(или--archive): Включает режим архивирования. Этот параметр действует как набор ключей, заставляющихrsyncкопировать рекурсивно, сохранять символические ссылки, разрешения, время последнего изменения файла, атрибуты владения и копировать специальные файлы.-v(или--verbose): Активирует подробный режим, выводя имена файлов по мере их копирования.--delete: Этот параметр критически важен для синхронизации (зеркалирования). Он гарантирует, что если какие-то файлы были удалены из исходного каталога, они будут удалены и из резервной копии (целевого каталога).- Синтаксис слэшей (
/):Важно обратить внимание на завершающий слэш (/) в конце исходного каталога (/path/to/source_dir/). - Если слэш в конце исходного каталога присутствует,
rsyncскопирует только содержимое каталогаsource_dirвdestination_dir. - Если слэш отсутствует,
rsyncскопирует сам каталогsource_dirвнутриdestination_dir, что приведет к структуре/path/to/destination_dir/source_dir/.
Примечание об эффективностиrsync:rsyncиспользует быструю проверку, основываясь на комбинации размера файла и даты его последнего изменения, чтобы определить, нуждается ли файл в передаче.
Шаг 2: Создание Bash-сценария
Для автоматического выполнения рутинной работы, такой как синхронизация, администраторы часто создают сценарии (скрипты). Скрипт — это простой список команд системы, записанный в файл.
- Создайте файл сценария: Назовите файл, например,
sync_dirs.sh, и откройте его в текстовом редакторе. - Напишите сценарий: Сценарий должен начинаться со строки sha-bang (
#!/bin/bash), чтобы указать, какой интерпретатор командной оболочки использовать.
#!/bin/bash # Определение исходного и целевого каталогов SOURCE_DIR="/path/to/source_dir/" # Важно: убедитесь в наличии завершающего слэша! DEST_DIR="/path/to/destination_dir/" # Проверка, что исходный каталог существует (по желанию, для надежности) if [ ! -r "$SOURCE_DIR" ] ; then echo "Исходный каталог $SOURCE_DIR не существует или не читается. Синхронизация прервана." 1>&2 # Перенаправление вывода ошибки exit 1 fi # Выполнение синхронизации с rsync /usr/bin/rsync -av --delete "$SOURCE_DIR" "$DEST_DIR" # Вы можете добавить логирование, чтобы записывать результаты rsync: # /usr/bin/rsync -av --delete "$SOURCE_DIR" "$DEST_DIR" >> /var/log/sync_log.txt 2>&1
- Сделайте сценарий исполняемым: После сохранения файла ему необходимо установить права на выполнение с помощью команды
chmod:
chmod +x sync_dirs.sh
Шаг 3: Автоматизация запуска с помощью cron
Планировщик заданий crond (или cron) — это традиционный демон, который запускается как фоновый процесс и выполняет команды по расписанию, заданному в файлах crontab.
- Откройте или создайте таблицу
crontab: Для создания или редактирования личного файла запланированных команд используйте командуcrontab -e. - Добавьте запись синхронизации: Запись в файле
crontab(задание cron) состоит из шести полей: минуты, часы, день месяца, месяц, день недели, и сама команда. - Пример для ежедневной синхронизации в 03:15 утра:
# m h dom mon dow command 15 03 * * * /path/to/sync_dirs.sh
15: Минуты (0–59).03: Часы (0–23).*: День месяца (1–31). Звездочка означает "каждый день".*: Месяц (1–12). Звездочка означает "каждый месяц".*: День недели (0–6, где 0 или 7 — воскресенье). Звездочка означает "каждый день недели".- Когда вы сохраните файл и выйдете из редактора, команда запустится автоматически программой
cronв соответствии с заданным расписанием.
Альтернативные методы автоматизации
- Системные каталоги
cron: Вы можете разместить исполняемый сценарий синхронизации в специальных системных каталогах, которые запускаются демономcrondавтоматически: /etc/cron.hourly(ежечасно)/etc/cron.daily(ежедневно)/etc/cron.weekly(еженедельно)/etc/cron.monthly(ежемесячно)- Например, для ежедневной синхронизации достаточно скопировать исполняемый сценарий в
/etc/cron.daily. - Планировщик
systemd.timer: Это современная реализацияcron. Для выполнения периодического сценария требуется файл службы (.service) и файл таймера (.timer), которые должны быть помещены в/etc/systemd/system. Юниты таймера мощнее, чем записиcrontab, но их сложнее настраивать.
Шаг 4: Резервное копирование с использованием жестких ссылок (--link-dest) (для создания моментальных снимков)
Если вы хотите не просто синхронизировать две директории, а создавать серию инкрементальных резервных копий (снэпшотов), которые занимают мало места, rsync может использовать жесткие ссылки.
Параметр --link-dest использует жесткие ссылки для создания серии ежедневных резервных копий, которые занимают очень мало дополнительного места.
- Если файл не изменился со вчерашнего дня, создается жесткая ссылка на него в новой директории. Жесткие ссылки указывают на те же данные на жестком диске.
- Если файл изменился, создается новая копия, и только изменения копируются.
Это позволяет создавать полную структуру каталогов для каждого дня, при этом используя минимальное дополнительное пространство.
Пример команды rsync с использованием --link-dest (для ежедневного бэкапа):
Предположим, вы хотите делать ежедневный бэкап из /home/user/data/ в целевой каталог /backup/snapshots/. Вы должны запускать этот скрипт каждый день, используя текущую дату для создания новой папки, и указывать предыдущую дату в качестве цели для ссылок:
# Определяем каталоги SOURCE_DIR="/home/user/data/" TODAY_DIR="/backup/snapshots/$(date +%Y-%m-%d)/" YESTERDAY_DIR="/backup/snapshots/$(date -d 'yesterday' +%Y-%m-%d)/" # Выполняем синхронизацию /usr/bin/rsync -av --delete --link-dest="$YESTERDAY_DIR" "$SOURCE_DIR" "$TODAY_DIR"
(Примечание: Использование date -d 'yesterday' или аналогичной конструкции зависит от версии bash и утилит, но источник описывает общий принцип с помощью --link-dest=../backup.1.)
Такой сценарий также должен быть автоматизирован с помощью cron (например, запускаясь ежедневно в 03:15).
Как реализовать скрипт синхронизации, включая проверку аргументов, логирование и продвинутое создание резервных копий.
1. Базовый сценарий синхронизации с rsync
Для автоматической синхронизации файлов наиболее эффективным инструментом является rsync. Он передает только изменения в файлах, что делает его быстрым.
Предположим, мы хотим зеркалировать каталог /data/source/ в /data/destination/.
Пример 1. mirror_sync.sh (Сценарий полного зеркалирования)
#!/bin/bash # mirror_sync.sh: Сценарий для полного зеркалирования двух директорий. # 1. Определяем переменные (для удобства модификации) SOURCE_DIR="/data/source/" DEST_DIR="/data/destination/" LOGFILE="/var/log/rsync_mirror.log" # Важно: завершающий слэш в SOURCE_DIR означает, что копируется # только СОДЕРЖИМОЕ каталога, а не сам каталог. # 2. Основная команда rsync: # -a: Режим архивирования (рекурсивное копирование, сохранение прав, владельцев, меток времени) # -v: Подробный вывод # --delete: Удаляет файлы в DEST_DIR, если они отсутствуют в SOURCE_DIR (зеркалирование) /usr/bin/rsync -av --delete "$SOURCE_DIR" "$DEST_DIR" >> "$LOGFILE" 2>&1 # 3. Проверка результата выполнения # $? содержит код возврата (0 = успех, >0 = ошибка) if [ $? -eq 0 ]; then echo "$(date +%Y-%m-%d\ %H:%M:%S): Synchronization completed successfully." >> "$LOGFILE" exit 0 else echo "$(date +%Y-%m-%m\ %H:%M:%S): Synchronization FAILED!" >> "$LOGFILE" exit 1 fi
Важные моменты Bash:
- Сценарии оболочки (скрипты) обычно начинаются с
#!/bin/bash. - Использование логических операторов
if [ $? -eq 0 ](если код завершения равен нулю) позволяет выполнять команды, зависящие от успеха предыдущей операции. - Операторы перенаправления
>> "$LOGFILE" 2>&1добавляют (>>) стандартный вывод (stdout) и стандартный вывод ошибок (2>&1) в лог-файл.
2. Запуск по расписанию с помощью cron
Для регулярного запуска сценарий должен быть добавлен в планировщик заданий crond. Любой пользователь может создать собственную таблицу crontab.
- Сделайте сценарий исполняемым:
chmod +x /path/to/mirror_sync.sh
- Откройте crontab:
crontab -e
- Добавьте запись: Формат записи
crontabвключает пять полей времени (минуты, часы, день месяца, месяц, день недели) и команду:
# Ежедневная синхронизация в 01:00 ночи # м ч дм мес дн команда 0 1 * * * /path/to/mirror_sync.sh
- Использование звездочки (
*) означает "каждое значение".
Альтернатива crontab: Сценарий также можно разместить в специальных системных каталогах, которые демон crond запускает автоматически:
/etc/cron.hourly(ежечасно)/etc/cron.daily(ежедневно)/etc/cron.weekly(еженедельно)/etc/cron.monthly(ежемесячно)
Если нужно создать более гибкое расписание (например, в 7:00 и 7:20), следует использовать записи в файле /etc/crontab или в личном crontab -e.
3. Расширенный сценарий: Инкрементальные резервные копии (Снимки)
Для создания серии резервных копий, которые занимают мало места, rsync может использовать жесткие ссылки (--link-dest). Этот метод позволяет создавать полные, доступные копии данных для каждого дня, при этом копируются только измененные файлы, а неизмененные связываются жесткими ссылками с предыдущими копиями.
Пример 2. snapshot_sync.sh (Сценарий с ротацией и жесткими ссылками)
Этот сценарий имитирует ротацию на основе нумерованных каталогов (backup.0, backup.1, backup.2 и т.д.), как это описано в источнике (Пример A-32).
#!/bin/bash
# snapshot_sync.sh: Создание инкрементальных снимков с ротацией (3 дня)
SOURCE_DIR="/home/local_data" # ВАЖНО: Без завершающего слэша, если вы хотите создать
# в конечном каталоге /data/snapshot/backup.N/local_data
BACKUP_BASE="/data/snapshots/"
LOGFILE="/var/log/rsync_snapshot.log"
DATE_FORMAT="+%Y-%m-%d %H:%M:%S"
# Определяем каталоги для работы:
# backup.0 - Сегодняшний рабочий снимок
# backup.1 - Вчерашний снимок (для создания жестких ссылок)
CURRENT_COPY="$BACKUP_BASE/backup.0/"
PREVIOUS_COPY="$BACKUP_BASE/backup.1/"
# Проверка и создание базовой директории
/bin/mkdir -p "$BACKUP_BASE"
# 1. Сначала проверяем существование предыдущей копии
# Если backup.1 существует, используем ее для жестких ссылок
LINK_DEST_OPT=""
if [ -d "$PREVIOUS_COPY" ]; then
# Если предыдущая копия существует, задаем ее как цель для ссылок.
# Обратите внимание на относительный путь '../backup.1', как в примере.
LINK_DEST_OPT="--link-dest=../backup.1/"
echo "$(date $DATE_FORMAT): Using $PREVIOUS_COPY for hard links." >> "$LOGFILE"
fi
# 2. Выполняем синхронизацию
# -S: Управление разреженными файлами (sparse files)
# --delete: Удаляем то, что удалено в источнике
# --modify-window=60: Игнорировать различия во времени в пределах 60 секунд (для надежности)
/usr/bin/rsync -a -S --delete --modify-window=60 \
$LINK_DEST_OPT \
"$SOURCE_DIR" "$CURRENT_COPY" 2>&1 | /usr/bin/tee -a "$LOGFILE"
RET=$? # Получаем код завершения rsync
if [ $RET -eq 0 ]; then
echo "$(date $DATE_FORMAT): Snapshot successful. Starting rotation." >> "$LOGFILE"
# 3. Ротация (переименование старых копий)
# Используем логические списки (&&) для последовательности команд:
/bin/rm -rf "$BACKUP_BASE/backup.3/" && \
/bin/mv "$BACKUP_BASE/backup.2/" "$BACKUP_BASE/backup.3/" && \
/bin/mv "$BACKUP_BASE/backup.1/" "$BACKUP_BASE/backup.2/" && \
/bin/mv "$BACKUP_BASE/backup.0/" "$BACKUP_BASE/backup.1/"
echo "$(date $DATE_FORMAT): Rotation finished." >> "$LOGFILE"
exit 0
else
echo "$(date $DATE_FORMAT): Snapshot FAILED! Code: $RET. Check previous output." >> "$LOGFILE"
# В случае ошибки можно сохранить неудавшуюся копию, как "justincase".
exit $RET
fi
Объяснение механизмов Bash в примере 2:
- Переменные и пути: Используются переменные для определения путей (
$SOURCE_DIR,$BACKUP_BASE), что упрощает модификацию сценария. - Условная логика (
if): Проверяется, существует ли предыдущая копия, чтобы корректно сформировать опцию--link-dest. - Конвейер и
tee: Вывод командыrsyncперенаправляется вtee -a "$LOGFILE". Это позволяет одновременно отображать вывод в стандартном потоке (если скрипт запускается вручную) и добавлять (-a) его в лог-файл. - Цепочка команд (
&&): В блоке ротации командыmvиrmсоединены с помощью&&. Это гарантирует, что следующая команда выполнится, только если предыдущая завершилась успешно (статус возврата 0).
4. Синхронизация между сетевыми машинами (SSH)
rsync может безопасно синхронизировать файлы между двумя сетевыми машинами, используя SSH в качестве транспортного протокола.
Пример 3. remote_sync.sh (Синхронизация через SSH)
Для автоматического запуска через cron без запроса пароля необходимо настроить аутентификацию по SSH-ключам без парольной фразы.
#!/bin/bash
# remote_sync.sh: Копирование локального каталога на удаленный сервер через SSH
LOCAL_SOURCE="/home/duchess/Music/"
REMOTE_USER="empress"
REMOTE_HOST="laptop"
REMOTE_DEST="/backups/songs/"
# Команда rsync для отправки файлов на удаленный хост:
# Параметры те же (-a), SSH используется по умолчанию в современных системах.
/usr/bin/rsync -avz --partial --progress \
"$LOCAL_SOURCE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DEST"
# Ключи:
# -a: Архивация
# -v: Подробно
# -z: Сжатие (полезно для сети)
# --partial: Сохранять частично скачанные файлы
# --progress: Отображать ход передачи
# Дополнительный вариант (если требуется явно указать SSH-ключ для cron):
# /usr/bin/rsync -ae "ssh -i /home/duchess/.ssh/id-server1" \
# "$LOCAL_SOURCE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DEST"
Передача данных с удаленной машины на локальную (pull): Для получения файлов с удаленной машины, просто поменяйте местами источник и назначение:
# Получение каталога /logs с server1 в локальный /var/log/
/usr/bin/rsync -avz --delete \
"root@server1:/var/log/app_logs/" "/var/log/local_backups/"