Вопрос или проблема
У меня есть следующий скрипт, использующий rsync
для резервного копирования и синхронизации моих файлов.
Как я могу сделать этот скрипт более компактным, быстрым и с лучшей обработкой ошибок?
#!/bin/sh
errors=""
sudo rsync -avh --delete --no-o --no-g /home/xralf/audio /media/extdevice/rsync_backups/
if [ "$?" -eq "0" ]
then
echo "нет ошибок в аудио"
else
errors="${errors}ошибка в аудио\n"
fi
sudo rsync -avh --delete --no-o --no-g /home/xralf/books /media/extdevice/rsync_backups/
if [ "$?" -eq "0" ]
then
echo "нет ошибок в книгах"
else
errors="${errors}ошибка в книгах\n"
fi
sudo rsync -avh --delete --no-o --no-g /home/xralf/source_code /media/extdevice/rsync_backups/
if [ "$?" -eq "0" ]
then
echo "нет ошибок в исходном коде"
else
errors="${errors}ошибка в исходном коде\n"
fi
# больше таких каталогов с этой кодовой структурой
echo ${errors}
Позже я планирую не следить за выполнением скрипта, так что я хотел бы видеть только результат и верить, что все прошло хорошо.
Я запустил скрипт, но в итоге единственная информация, которую я получил, это ошибка в исходном коде
, и я не могу понять, в чем именно ошибка (какой файл ее вызвал).
Если ваш приоритет — быть компактным и быстрым (т.е. минимизируя количество процессов, но в этом случае вы ограничены вводом-выводом диска, а не ЦП или памятью):
#!/bin/bash
sudo rsync -a --delete --no-o --no-g \
/home/xralf/{audio,books,source_code} \
/media/extdevice/rsync_backups/ &&
echo "rsync выполнен успешно" 1>&2 || echo "rsync завершился с ошибками" 1>&2
Удаление опции -v
сделает вывод менее шумным, так что вы сможете сосредоточиться на явных ошибках, если они есть. Перенаправление 1>&2
отправляет STDOUT в STDERR, так что сообщения об ошибках отправляются туда, где ожидаются. Если выполнять без наблюдения, следующие альтернативы могут оказаться лучшими вариантами, чем встроенная echo
, за счет одного дополнительного процесса:
-
сервер может использовать
logger
для отправки сообщения вsyslog
для централизованной обработки. Точная синтаксис будет зависеть от конфигурации сервера. -
использование
date
для добавления временной информации, с последней строкой скрипта:
date +"[%Y/%m/%d %H:%M:%S] rsync выполнен успешно" 1>&2 || \
date +"[%Y/%m/%d %H:%M:%S] rsync завершился с ошибками" 1>&2
для вывода чего-то вроде [2022/12/05 14:37:27] rsync выполнен успешно
Если вы не обязаны использовать sh
, но можете использовать более сложный оболочку, такой как bash
, вы можете сделать что-то вроде этого:
#!/bin/bash
dirs=( "audio" "books" "source_code" );
errors=()
for dir in "${dirs[@]}"; do
sudo rsync \
-avh --delete --no-o --no-g \
/home/xralf/"$dir" \
/media/extdevice/rsync_backups/ &&
echo "нет ошибок в $dir" ||
errors+=("ошибка в $dir\n")
done
printf '%s\n' "${errors[@]}"
Вы, вероятно, также хотите захватить stderr, но это делает то же самое, что и ваш скрипт.
Команда rsync
принимает параметр --log-file=FILE
. Вы можете проверить его на наличие ошибок, когда резервное копирование завершено.
Для повышения эффективности она также принимает --exclude-from=FILE
и --include-from=FILE
. Вы можете создать текстовые файлы, содержащие список всего, что вы хотите и не хотите резервировать, и вызывать их из одной команды rsync
вместо нескольких.
Смотрите man rsync
или онлайн-страницу man.
Создайте файл с именем module.sh и дайте ему следующий текст:
#!/usr/bin/env bash
# -A=Архив. Используйте рекурсию и сохраняйте почти все.
# -V=Подробно.
# -H=Сохранять жесткие ссылки.
# -Z=Сжимать.
# --Delete=
# Если узел в каталоге 'from' удаляется,
# удалить его в каталоге 'to'.
# --No-o=Нет владельца.
# --No-g=Нет группы.
# Опции --No частично отменяют опцию Архив.
sync_dir(){
local from="${1}";
local to="${2}";
rsync \
-avhz \
--delete \
--no-o \
--no-g \
"${from}/" \
"${to}" \
1>/dev/null \
;
# Сохраните результат синхронизации.
local sync_result="${?}";
# Имя проекта — это последний каталог из строки from.
local project_name=$(grep -oE '[^/]*$' <<<"${from}");
local error="Нет ошибок в: ${project_name}";
if [ "${sync_result}" -ne "0" ]; then
error="Ошибка в: ${project_name}\n";
fi
printf "${error}\n";
};
Затем вы создаете другой файл и подключаете модуль оттуда:
#!/usr/bin/env bash
. ./module.sh;
sync_dir '/home/xralf/audio' '/media/extdevice/rsync_backups/';
# Больше каталогов синхронизации здесь.
Обратите внимание на другой Shebang, этот соответствует POSIX.
Я также добавил опцию -z для Rsync. Она сжимает данные по пути.
Ответ или решение
Оптимизация скрипта для rsync: Быстрее, компактнее и с лучшей обработкой ошибок
Введение
Параметры резервного копирования и синхронизации данных играют ключевую роль в администрировании систем. Программа rsync
– мощный инструмент для данной задачи, однако к скрипту, который использует этот инструмент, следует подходить с осторожностью, чтобы он был как можно более эффективным и надежным. В данной статье мы рассмотрим, как улучшить ваш скрипт на основе rsync
, сделать его более компактным, быстрым и с лучшей обработкой ошибок.
Проблема
Ваш текущий скрипт обрабатывает несколько директорий по очереди и сохраняет ошибки в отдельной переменной. Однако, если в процессе синхронизации возникает ошибка, вы не получаете полной информации о том, что именно пошло не так, и это затрудняет процесс диагностики. Кроме того, повторяющийся код делает ваш скрипт более тяжелым и менее понятным.
Оптимизированный подход
1. Использование массивов
Первый шаг к сокращению кода и улучшению его читаемости – использование массивов для хранения директорий. Это позволит вам избавиться от повторяющегося кода.
#!/bin/bash
dirs=( "audio" "books" "source_code" )
errors=()
for dir in "${dirs[@]}"; do
if sudo rsync -avh --delete --no-o --no-g "/home/xralf/$dir" "/media/extdevice/rsync_backups/"; then
echo "Без ошибок в директории $dir."
else
errors+=("Ошибка в директории $dir.")
fi
done
# Вывод всех ошибок в конце
if [ ${#errors[@]} -gt 0 ]; then
printf '%s\n' "${errors[@]}"
else
echo "Все директории успешно синхронизированы."
fi
2. Логирование операций
Для более удобного анализа ошибок целесообразно использовать логирование команд rsync. Вы можете записывать вывод в файл, чтобы позже проанализировать, что именно пошло не так.
rsync ... --log-file=/path/to/logfile.log
3. Использование параметра –exclude-from и –include-from
Если ваши операции резервного копирования затрагивают множество файлов, рекомендуется использовать файлы для исключений и включений. Это поможет избежать повторения однотипного кода и сделает его более управляемым.
4. Добавление временных меток
Для повышения информативности логов можете добавлять временные метки к выводимым сообщениям. Это также упростит отладку в будущем:
date +"[%Y/%m/%d %H:%M:%S] Без ошибок в директории $dir." >> /path/to/logfile.log
5. Обработка ошибок
Оптимизировав обработку ошибок, мы можем дополнительно выводить информацию о конкретных ошибках:
if ! rsync ...; then
echo "Ошибка при синхронизации $dir. Проверяйте логи." >> /path/to/logfile.log
fi
Заключение
Используя указанные методы, вы сможете создать более компактный, быстрый и информативный скрипт для rsync
. Оптимизация скрипта является не только улучшением его производительности, но и упрощением процесса диагностики ошибок, что, в свою очередь, ведет к более надежной работе резервного копирования. Не забывайте также проверять актуальность документации rsync
и применять новые возможности по мере их появления.