В этой статье я на конкретных практических примерах покажу как работать с утилитой RSync в Linux.
RSync - это очень быстрый и мощный инструмент для работы с файлами и каталогами как на локальном компьютере, так и на удалённом сервере.
С одной стороны RSync - это лёгкая (в плане потребления ресурсов) и многофункциональная утилита с широкими возможностями - незаменимый инструмент системного администратора, с другой же стороны для новичков и не сильно продвинутых пользователей Линукс RSync может показаться очень сложным, замудрёным и непонятным.
Поэтому мы будем здесь разбирать простые примеры и на них учиться работать с RSync.
Для этого возьмём практическую и довольно часто встречающуюся задачу - синхронизацию файлов и папок на локальном компьютере (сервере). Это бывает нужно не только сисадмину на сервере, но и обычным пользователям на домашнем/рабочем компьютере или ноутбуке. Например, надо перенести рабочий проект (несколько файлов и папок) на флешку, потом на домашний компьютер, дома поработать и затем только новые или измененные файлы снова скопировать на флешку, ну а после этого сделать синхронизацию с рабочим компьютером. Или, например, синхронизация своей личной библиотеки между ноутбуком и домашним компьютером, причём, какие-то книги могут быть изначально закачаны на ноутбук, а какие-то на домашний компьютер. И надо это всё привести к единообразию: чтобы там и там были все книги. Или, например, копирование своего фотоальбома на внешний жесткий диск.
Как видим, задача синхронизации встречается очень часто и может иметь самое разное практическое применение.
Вы можете как раз взять для себя именно ту задачу, которую вам и необходимо решить. А я для примера возьму вот такую задачу: создание архива всех установленных программ (пакетов), чтобы они всегда были под рукой и в случае переустановки системы не нужно было их заново выкачивать. Делать это сохранение мы будем по мере установки новых программ (пакетов) или же обновления уже имеющих. Практически в каждом дистрибутиве Линукс имеется специальный каталог, в котором временно хранятся все скачанные пакеты. В дистрибутивах семейства Дебиан (Debian, Ubuntu, Lubuntu, Linux Mint и другие) это будет каталог: /var/cache/apt/archives
Вот так сейчас этот каталог выглядит на моей тестовой машине:
Создадим папку на другом диске для копирования туда этих файлов и дальнейшей синхронизации:
$ mkdir /media/testuser01/SecondDisk/PackagesBackup
Сейчас эта папку пустая. Сделаем первую синхронизацию.
$ rsync -vh --progress /var/cache/apt/archives /home/myusername/PackagesBackup
Здесь я использовал ключи (options):
-v (verbose) - вывод более детальной информации о производимых действиях
-h (human-readable) - вывод чисел в удобочитаемом формате
--progress - показать прогресс во время передачи
Первый путь "/var/cache/apt/archives" - каталог-источник (source)
И вот здесь внимательный читатель конечно же заметил, что второй путь ошибочный. "/home/myusername/PackagesBackup" - это не существующий путь и подкаталога "/myusername" в каталоге "/home" не существует (также как не существует и пользователя с таким именем).
Да, я намеренно ввёл неверный путь каталога-приёмника (destination), так как мы сейчас смотрим, учимся, изучаем и нам важно знать не только как делать правильно, но и что произойдет, если ввести что-то не верно. А ошибки в ключах, опечатки часто бывают и в реальной практике. Поэтому мы в некоторых случаях будем намеренно создавать ошибочные ситуации, чтобы знать что будет происходить, а также чтобы по соответствующей реакции системы и сообщениям об ошибках сразу видеть в чём именно ошибка и как её исправить.
Система нам в этом примере совершенно верно вывела сообщение об ошибке: "failed: No such file or directory". Т.е. не удалось выполнить операцию: нет такого файла или каталога.
Теперь введем команду с частично правильным путём каталога-приёмника:
$ rsync -vh --progress /var/cache/apt/archives /media/testuser01/PackagesBackup
Здесь уже путь "/media/testuser01" существует, а вот подкаталога "/PackagesBackup" в нём нет. И система не выдаёт столь грозных сообщений об ошибках, но и действий никаких не производит: никакие файлы или каталоги никуда не копируются.
Ну чтож, давайте теперь уже введём наконец команду с правильным путём каталога-приёмника:
$ rsync -vh --progress /var/cache/apt/archives /media/testuser01/SecondDisk/PackagesBackup
Но и в этом случае никаких действий произведено не было, никакие файлы или каталоги никуда не скопировались. Хотя путь задан верно и простая проверка командой ls покажет, что такой путь существует.
Так в чём же тогда дело?
Внимательно смотрим на предупреждение, которое выдала нам система: "skipping directory archives" - т.е. каталог "archives" был пропущен.
И дел здесь в том, что команда rsync синхронизирует прежде всего файлы, а не каталоги (каталоги тоже, но об этом ниже). А мы в качестве источника не задали никаких файлов, а указали только каталог. Чтобы задать файлы нужно указать вот такой путь источника: "/var/cache/apt/archives/*" Т.е. выбрать все файлы в подкаталоге "archives". А полностью команда будет выглядеть так:
$ rsync -vh --progress /var/cache/apt/archives/* /media/testuser01/SecondDisk/PackagesBackup
И сразу же команда заработала, файлы скопировались. Правда тоже есть предупреждения и сообщения об ошибках - их мы разберем чуть позже. А пока проверим, точно ли все файлы скопировались в нашу папку "PackagesBackup".
Да, действительно, почти все файлы скопировались. Если мы вернёмся в начало и посмотрим снова на содержимое каталога-источника (/var/cache/apt/archives), то увидим, что там есть ещё один файл "lock" и подкаталог "partial". Собственно предупреждение "skipping directory partial" как раз и говорит о том, что этот каталог был пропущен. Что же касается файла "lock" то здесь в процессе выполнения операций копирования тоже видим предупреждение "Permission denied" (см. скриншот выше), т.е. нет доступа. А доступа нет из-за недостаточных разрешений или ограниченных прав текущего пользователя.
Выполним ту же команду от суперпользователя:
$ sudo rsync -vh --progress /var/cache/apt/archives/* /media/testuser01/SecondDisk/PackagesBackup
Опция "--recursive" - обработка подкаталогов
И теперь видим, что сообщения об ошибках уже не выдаются, все файлы и даже файл "lock" скопировались. А вот каталог "partial" так и нет.
И тут нет никакой ошибки, команда задана верно. Просто по умолчанию rsync копирует (пересылает) только файлы, а все каталоги пропускает. Чтобы rsync копировала и каталоги надо дать ей такое указание, т.е. добавить в команду соответствующий ключ (option). Это ключ -r или --recursive - все подкаталоги (и подкаталоги подкаталогов т.е. рекурсивно) указанного каталога-источника.
Выполним команду с добавлением ключа -r:
$ sudo rsync -rvh --progress /var/cache/apt/archives/* /media/testuser01/SecondDisk/PackagesBackup
Вот наконец-то мы видим, что все имеющиеся файлы и каталоги из источника скопированы в приёмник. Проверка через ls это подтверждает:
Особенности синтаксиса - завершающий слеш.
Здесь важно отметить одну интересную особенность утилиты rsync.
А именно, теперь когда мы запускаем её с ключом -r т.е. рекурсивно, звёздочку в конце ставить не обязательно.
Вот такой синтаксис тоже будет правильным и команда отработает верно:
$ sudo rsync -rvh --progress /var/cache/apt/archives/ /media/testuser01/SecondDisk/PackagesBackup
А вот завершающий слеш в указании пути каталога-источника ставить обязательно. Иначе команда скопирует не содержимое каталога "archives", а весь каталог целиком. Т.е. таким образом получится "вложенное дублирование".
Ну раз мы сейчас учимся, то давайте запустим и неправильный вариант (без слеша в конце) и посмотрим что получится:
$ sudo rsync -rvh /var/cache/apt/archives /media/testuser01/SecondDisk/PackagesBackup
В результате получаем вот такое вложенное задваивание файлов:
Вот такая, казалось бы, незначительная деталь в синтаксисе команды играет очень большое значение!
С этим разобрались. Идём дальше.
Проблема перезаписи и как RSync сравнивает файлы?
Как RSync разрешает конфликты?
Ну вот вроде бы всё теперь хорошо и мы добились своей цели: все файлы и папки успешно копируются, никаких ошибок и предупреждений нет, - всё замечательно. Но не совсем. Что же не так? Чего ещё не хватает?
Давайте смотреть.
Если мы ещё раз запустим на выполнение туже самую команду:
$ sudo rsync -rvh --progress /var/cache/apt/archives/* /media/testuser01/SecondDisk/PackagesBackup
То она ещё раз выполнится и ещё раз будет копировать все файлы и каталоги, а имеющиеся там файлы будут перезаписаны. Но они ведь уже есть в каталоге назначения (приёмнике), так зачем же их ещё раз копировать?
В самом деле, они ведь не были изменены - это те же самые файлы.
Кто-то может сказать: "Ну а в чём проблема? Пусть копируются и перезаписываются." Да, для нашего простого примера это не сильно критично. Но ведь в реальной ситуации могут синхронизироваться тысячи и десятки тысяч файлов, например, альбомы фотографий за несколько лет, или же файлы большого объёма 30-50ГБ или больше каждый файл, а в совокупности объёмом 5000-10000ГБ и более. А это уже серьезно. Каждый раз гонять такие объёмы данных не только не целесообразно, но и расточительно так, по сути впустую, нагружать компьютер. А если ещё при этом используются SSD-накопитель, то его вообще можно быстро убить такой вот "синхронизацией файлов".
Ну и наконец, методологически это тоже не правильно.
И тут возникает резонный вопрос: а что сама утилита rsync не "видит", не "понимает" что это те же самые файлы? Неужели такой мощный инструмент не может выполнить элементарную функцию - сравнения файлов?
Тут мы подошли к очень важному моменту.
Каким образом rsync сравнивает файлы и сравнивает ли вообще (или говоря по-другому проверяет на дублирование) ?
Этот вопрос мы и будем рассматривать дальше, как всегда, подробно и на конкретных примерах.
А каким образом вообще можно сравнить файлы и понять одинаковые это файлы или всё-таки разные?
На самом деле это отдельная большая тема и я не буду её здесь рассматривать полностью. Здесь я напишу только конкретные практические моменты применительно к утилите rsync.
Если говорить коротко, то сравнивать файлы можно по следующим параметрам:
- по наименованию файлов;
- по размеру файлов;
- по контрольным суммам;
- по дате создания;
- по дате последнего доступа;
- по дате изменения;
- по дате модификации
Последние три параметра называются временные метки файла (Access, Modify, Change).
Ну давайте не будем долго теоритезировать, а сделаем сравнение двух каких-нибудь файлов из тех, что мы синхронизировали утилитой rsync.
Например, сравним размеры файлов в байтах в каталоге-источнике и в каталоге-приёмнике. Для этого выполним две команды:
$ du -b /var/cache/apt/archives/pcmanfm_1.2.5-3_amd64.deb
$ du -b /media/testuser01/SecondDisk/PackagesBackup/pcmanfm_1.2.5-3_amd64.deb
Как мы видим, размеры файлов в точности одинаковые.
Давайте сравним контрольные суммы (checksum) файлов. Сделать это можно разными способами. Мы сделаем это самым простым и быстрым способом. А именно, воспользуемся командами md5sum, sha1sum, sha256sum:
$ md5sum /var/cache/apt/archives/pcmanfm_1.2.5-3_amd64.deb
$ md5sum /media/testuser01/SecondDisk/PackagesBackup/pcmanfm_1.2.5-3_amd64.deb
$ sha1sum /var/cache/apt/archives/pcmanfm_1.2.5-3_amd64.deb
$ sha1sum /media/testuser01/SecondDisk/PackagesBackup/pcmanfm_1.2.5-3_amd64.deb
$ sha256sum /var/cache/apt/archives/pcmanfm_1.2.5-3_amd64.deb
$ sha256sum /media/testuser01/SecondDisk/PackagesBackup/pcmanfm_1.2.5-3_amd64.deb
Контрольные суммы файлов также совпадают. Т.е. у нас два полностью идентичных (по содержимому) файла: и размер файлов и контрольные суммы в точности совпадают. Остальные файлы каталога-источника и каталога-приёмника можно сравнить таким же способом и убедиться, что и остальные файлы полностью идентичны.
И тем не менее, утилита rsync почему-то "не понимает", что файлы идентичны и каждый раз их заново перезаписывает.
Теперь давайте сравним атрибуты файлов, а именно временные метки файлов (access, modify, change). В этом нам поможет команда stat.
$ stat /var/cache/apt/archives/pcmanfm_1.2.5-3_amd64.deb
$ stat /media/testuser01/SecondDisk/PackagesBackup/pcmanfm_1.2.5-3_amd64.deb
И здесь мы можем увидеть очень интересную и важную для нас информацию. По умолчанию при копировании (синхронизации) утилита rsync каждый раз перезаписывает временные метки файлов. Временем последнего доступа к файлу (access), его модификации (modify) и изменения (change) становится время его копирования (текущее время в системе на момент копирования).
Опять же по умолчанию при копировании утилита rsync сравнивает файлы по временным меткам (конкретно по времени модификации), видит что файлы по этим параметрам отличаются и перезаписвает их, т.е. заново производит полное копирование всех файлов и подкаталогов.
Ну вот мы наконец-то и докопались до сути вопроса почему утилита rsync "не понимает", что файлы идентичны и каждый раз их заново перезаписывает. Осталось только найти решение, чтобы rsync понимала и не перезаписывала. А сделать это очень просто - нужно всего лишь добвать ключ -t или --times в команду. RSync с ключом -t сохраняте время модификации файла таким же, как и у исходного файла.
Давайте в этом убедимся. Выполним команду:
$ rsync -rvht --progress /var/cache/apt/archives/ /media/testuser01/SecondDisk/PackagesBackup
При этом все файлы у нас также перезапишутся.
И заново сравним атрибуты файлов командой stat:
$ stat /var/cache/apt/archives/pcmanfm_1.2.5-3_amd64.deb
$ stat /media/testuser01/SecondDisk/PackagesBackup/pcmanfm_1.2.5-3_amd64.deb
И теперь мы видим, что время модификации файлов в точности совпадает.
Ну и наконец, последний шаг. Запускаем нашу команду копирования (синхронизации) ещё раз. И, о чудо, видим что никаких действий не производится, никакие файлы или каталоги никуда не копируются.
Список скопированных (пересланных) файлов пуст (sending incremental file list).
Ура! Мы добились того, что хотели!
Давайте сделаем краткое резюме.
Итак, чтобы rsync "понимала", что файлы одинаковые и не перезаписывала их заново, нужно при первом запуске синхронизации исползовать ключ -t или --times. Тогда при копировании сохраняется время модификации файлов и при повторной синхронизации rsync "увидит" что файлы одинаковые.