bash: Бэкап без лишнего ПО

Бэкап важной информации — каждый системный администратор сталкивается с такой задачей. Задача казалось бы тривиальная и у многих читателей интереса не вызовет. Но, например, мне бы такая статья в определенный момент помогла бы весьма сильно, поэтому считаю, что этой статье быть.

Задача: Бэкап данных в локальную директорию и на отдельный сервер, с использованием минимума стороннего ПО, логированием и оповещением администратора в jabber при сбоях. Все основные функции большинства ПО для автоматического бэкапа, но без установки оного, а следовательно без его багов (что, собственно, и привело к подобной идее).

А теперь к делу.

Для начала создадим и откроем скрипт
nano backup-script

Теперь в скрипте добавим строку
#!/bin/bash

Объявим некоторые переменные.
TN — TASKNAME — имя задания.Используется для вывода в лог и определения названия файла.
Так как заданий несколько (ежемесячное, еженедельное, ежедневное) и писать на каждый случай скрипт было лень, я создал универсальный, в котором надо просто раскомментить нужные строки. Наименование заданий писать надо без пробелов, желательно в латинице, если не хотите проблем с кодировкой и неправильными параметрами команд.
TN=docs-monthly<br />
#TN=docs-weekly<br />
#TN=docs-daily

OF — Output File — имя выходного файла. Получается из переменной TN, то есть имени задания.
OF=$TN.tar.gz

Объявляем переменную с путем к файлу лога, и далее все сообщения об ошибках и остальном будем выводить в лог.
LOGFILE=/var/log/backup.log

Сделаем запись в лог о начале бэкапа (дата, время, имя задания)
echo  >>$LOGFILE
echo "====================================================="  >>$LOGFILE
echo "$(date +'%d-%b-%Y %R')" >>$LOGFILE
echo "Задание \"$TN\" запущено..." >>$LOGFILE

Есть проблема в том что если указывать в параметрах команд (напр. tar) имена каталогов с пробелами, скрипт срабатывает с ошибкой. Решение найдено на просторах интернета — операционная система linux использует пробел в качестве стандартного разделителя параметров команды. Переопределим стандартный разделитель (хранится в переменной $IFS) отличным от пробела, например \n – знаком переноса строки.
Запоминаем старое значение стандартного разделителя
OLD_IFS=$IFS

Заменяем стандартный разделитель своим
IFS=$'\n'

SRCD — SouRCe Directory — каталог с данными для бэкапа
Теперь можно перечислять несколько каталогов, разделителем будет перенос строк как мы сами указали строкой выше
SRCD="/mnt/source/folder_1
/mnt/source/folder_2
/mnt/source/folder_N"

TGTD — TarGeT Directory — каталог в который будут складываться бэкапы
TGTD="/var/backups/"

Естественно мы понимаем что хранить важные бэкапы только на источнике как минимум легкомысленно. Поэтому оставим копию и на удаленном ресурсе, который будем отдельно монтировать с помощью mount и fstab. Сразу поясню почему я использовал mount и fstab, а не один mount — я монтирую этот каталог и в других своих скриптах, а как сказал один из знакомых программистов — хороший программист не будет писать один и тот же код дважды (как-то так, дословно не помню, но надеюсь смысл донес).
TGTD2="/mnt/archive/"

Сам процесс архивирования в варианте "Создать новый архив"
tar -czf $TGTD$OF $SRCD &>>$LOGFILE

и в варианте "Обновить файлы в старом архиве"
tar -u -f $TGTD$OF $SRCD &>>$LOGFILE

Во втором случае лучше вместо $OF использовать конктретное имя файла потому что у меня например ежедневно апдэйтится еженедельный архив, а их $TN (имена задания) не совпадают, соответственно и $OF.

В переменной "?" ханится статус выполнения последней команды. Сохраним его, чтобы воспользоваться позже.
STATUS=$?

Возвращаем стандартный разделитель к исходному значению
IFS=$OLD_IFS

Теперь добавим условие — если процесс упаковки в архив tar закончился с ошибкой, отправляем сообщение админу, удаляем неудачный файл бекапа. Иначе продолжаем дальше — монтируем сетевую шару и кидаем в нее копию архива. После каждой операции проверяем результат выполнения, пишем логи, и либо продолжаем, либо извещаем админа и прерываем процедуру.
if [[ $STATUS != 0 ]]; then
    rm $TGTD$OF &>>$LOGFILE
    echo "###########################################" >>$LOGFILE
    echo "###  Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE
    echo "###########################################" >>$LOGFILE
    echo "$(date +'%d-%b-%Y %R%nФайл') бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE
else
    echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE
    echo "Бэкап успешно завершен в $(date +'%R %d-%b-%Y')!" >>$LOGFILE
    echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE
    mount $TGTD2 &>>$LOGFILE
    if [[ $? != 0 ]]; then
        echo "#############################################################" >>$LOGFILE
        echo "###  Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE
        echo "#############################################################" >>$LOGFILE
        echo "$(date +'%d-%b-%Y %R%nФайл') бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE
        exit
    fi
    echo "Начато копирование файла на резервный ресурс" >>$LOGFILE
    cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE
    if [[ $? != 0 ]]; then
        echo "#############################################################" >>$LOGFILE
        echo "###  Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE
        echo "#############################################################" >>$LOGFILE
        echo "$(date +'%d-%b-%Y %R%nФайл') бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE
    else
        echo "Копирование файла успешно завершено  в $(date +'%R %d-%b-%Y')!" >>$LOGFILE
        echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE
    fi
    echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE
    umount $TGTD2 &>>$LOGFILE
    echo "Все операции завершены успешно!" >>$LOGFILE
  fi
  exit


В процессе мы копируем архив из локального хванилища в удаленное. Естественно, проверяем, что каждая операция успешно завершена, и пишем все в логи.
Для отсылки сообщения администратору я использую XMPP сообщение, так как в организации поднят Jabber-сервер, и я больше люблю получить быстрое сообщение о сбое, чем лезть в почту, вбивая пароли, тыкая на ссылки, и ожидая пока браузер мне все отобразит. В любом случае никто не мешает вам использовать sendmail вместо sendxmpp.
Файл /usr/local/etc/XMPP_settings следующего содержания:

#логин_отправителя@домен;IP_jabber_сервера:порт_jabber_сервера пароль_отправителя
login@domen;127.0.0.1:5222 password

В файле fstab строка описывающая подключение шары Windows
//192.168.0.250/arhiv	/mnt/archive	cifs	noauto,rw,iocharset=utf8,cp866,file_mod=0666,dir_mod=0777,noexec,_netdev,credentials=/root/.passwd_to_archive_directory	0	0

Теперь осталось только добавить задание в cron. Это можно сделать с помощью файла /etc/crontab, но я, в силу привычки к GUI, оставшейся в наследство от виндовс, пользую вэб-интерфейсы для таких случаев. Команда должна выполняться с правами рута, то бишь, к примеру, sudo bash backup_script. Добавляя команду в cron можно определить что она будет сразу выполняться от имени root`а

В ходе обсуждений затронули проблему разрастания логов. Пошел по простейшему (на мой взгляд) пути: будем хранить только последние N строк лога, например 300. В скрипт добавятся две строки, в которых мы сохраним последние 300 строк лога во временный файл, потом затрем им лог
tail -n 300  $LOGFILE >/tmp/unique_fantastic_filename.tmp
mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE

Приведу полный текст скрипта:
#!/bin/bash

TN=docs-monthly 
#TN=docs-weekly
#TN=docs-daily

OF=$TN.tar.gz

LOGFILE=/var/log/backup.log

echo  >>$LOGFILE
echo "====================================================="  >>$LOGFILE
echo "$(date +'%d-%b-%Y %R')" >>$LOGFILE
echo "Задание \"$TN\" запущено..." >>$LOGFILE

OLD_IFS=$IFS

IFS=$'\n'

SRCD="/mnt/source/folder_1
/mnt/source/folder_2
/mnt/source/folder_N"

TGTD="/var/backups/"
TGTD2="/mnt/archive/"

tar -czf $TGTD$OF $SRCD &>>$LOGFILE
#tar -u -f $TGTD$OF $SRCD &>>$LOGFILE

STATUS=$?

IFS=$OLD_IFS

if [[ $STATUS != 0 ]]; then
    rm $TGTD$OF &>>$LOGFILE
    echo "###########################################" >>$LOGFILE
    echo "###  Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE
    echo "###########################################" >>$LOGFILE
    echo "$(date +'%d-%b-%Y %R%nФайл') бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE
else
    echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE
    echo "Бэкап успешно завершен в $(date +'%R %d-%b-%Y')!" >>$LOGFILE
    echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE
    mount $TGTD2 &>>$LOGFILE
    if [[ $? != 0 ]]; then
        echo "#############################################################" >>$LOGFILE
        echo "###  Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE
        echo "#############################################################" >>$LOGFILE
        echo "$(date +'%d-%b-%Y %R%nФайл') бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE
        exit
    fi
    echo "Начато копирование файла на резервный ресурс" >>$LOGFILE
    cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE
    if [[ $? != 0 ]]; then
        echo "#############################################################" >>$LOGFILE
        echo "###  Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE
        echo "#############################################################" >>$LOGFILE
        echo "$(date +'%d-%b-%Y %R%nФайл') бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE
    else
        echo "Копирование файла успешно завершено  в $(date +'%R %d-%b-%Y')!" >>$LOGFILE
        echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE
    fi
    echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE
    umount $TGTD2 &>>$LOGFILE
    echo "Все операции завершены успешно!" >>$LOGFILE
fi
tail -n 300  $LOGFILE >/tmp/unique_fantastic_filename.tmp
mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE
exit


Всем спасибо за внимание!

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 38

    +2
    Я иногда пользуюсь таким способом.
    ssh+rsync+git=простой удаленный инкрементальный бэкап.
    Скрипты не идеальны, но они справляются со своей задачей.
    BACKUP_DIR=/backup/
    backup() {
                    NAME=$1
                    SERVER=$2
                    PORT=$3
                    echo ""
                    echo "==========$NAME=========="
    
    		#создадим папку и проинициализируем git в первый раз
                    if [ ! -d $BACKUP_DIR$NAME ]; then
                                    mkdir $BACKUP_DIR$NAME
                                    cd $BACKUP_DIR$NAME;
                                    git init
                    else
                                    cd $BACKUP_DIR$NAME
                    fi
                    echo "prepare: `date`"
    		#заставим сервер сделать бэкап (БД, ldap и прочее. Что нельзя забирать напрямую с ФС).
                    ssh $SERVER -p $PORT /pathToScript/prepareBackup.sh
                    echo "rsync: `date`"
    		#забираем данные
                    rsync -avzh --compress-level=9 --delete --include-from=$BASEPATH$NAME -e "ssh -p $PORT" $SERVER:/ .
                    echo "git: `date`"
    		#добавляем в git
                    git add . > /dev/null
    		#коммитим
                    git commit -a  -mupdate > /dev/null
                    echo "complete: `date`"
    }
    
    backup "name1"  "some.host.name1" 22
    backup "name2"  "some.host.name2" 22
    

    файл name1 в том же каталоге:
    + /etc**
    + /var/
    + /var/backup**
    + /var/www
    + /var/www/host**
    - /var/www/host/excluded**
    - *
    

    Пример prepareBackup.sh:
    cd /var/backup/
    su postgres -c "pg_dump dbName -f dbName.sql"
    slapcat > ldap.ldif
    


    Можно завернуть вывод в файл или почту.

    Большой минус данного метода — авторизация по ключу без пароля.
      0
      Большой минус — история хранится с самого первого бекапа. И если в него попадет что-то лишнее и большого размера — оно там так и останется если не транкейтить git-репо периодически.
        0
        кстати, такая мысль при написании скрипта посещала, но я ее проигнорировал, поскольку в моем случае лог разрастается медленно, а в логах я бываю с некоторой периодичностью, то и файлик удалить вручную для меня не проблема. Поищу время дописать статью на предмет ротации логов.
        0
        я вот тоже пришел к rsync + ssh + cron

        tar закапывает проблему при появлении существенных объёмов.

        в остальном, конечно, велосипеды это всё. Либо игры при изучении линухов, либо спец задача (например, многоточечный бекап медиахранилища по узким каналам у меня).
        0
        Если не секрет, почему используется именно tar, а не dar?
        Просто периодически на хабре или других ресурсах встречаю скрипты бекапа, и везде tar + gz, хотя dar-то помощнее будет.
        И да, я не админ (область моей ответственности ограничивается домашним серваком с документами/фото и т.д.), поэтому интересуюсь, может это я чего-то не понимаю, а профессионалы по какой-то причине считают dar не кошерным :)
          +1
          Думаю что как минимум могут повлиять эти причины:
          1. В стандартных репозитариях его нет для установки и надо ручками собирать
          2. Будет больше грузить сервер при создании бекапа
          3. Не смотрел ключики и спецификацию, но в случае с tar его иногда очень удобно использовать без самого gzip для бэкапинга директорий с media контентом
          4. Сила привычки и повсеместности
            0
            Спасибо за ответ!
            Насчёт производительности ничего не могу сказать, не проверял. Но там тот же gz для сжатия применяется, а оно больше всего процессора ест. Не думаю, что из-за остального будут какие-то серьёзные различия в скорости.
            В управлении сжатием dar точно мощнее. У него в одном архиве могут быть файлы и сжатые и несжатые, причём из командной строки можно установить, какие не сжимать (фильтр по шаблону).

            А с причинами 1 и 4 всё ясно, тут не поспоришь :)
            Видимо, большое админство всё-таки свои проблемы имеет: я-то ни совместимостью, ни сборкой (на один-то сервак) могу не заморачиваться.
              0
              Ну у меня аналогичная по сути ситуация — 1 сервак + иногда помогаю клиентам по мелочам на серваке с настройками. Но что на клиентских что на своем (на моем только dev проекты) предпочитаю media и код хранить отдельными файлами, т.к. иногда бывает что возникает ситуация что именно в папке media нечаянно снесут что-либо и надо восстановить, а она сама в tar получается порядка 4 гигов. Код ещё 2 гига и в код уже могли быть внесены изменения со времени последнего бекапа
              Понятно что можно вынять только нужную папку, но на таких размерах все-равно чувствуется по скорости это.
              Хотя это конечно дело каждого. Ну а сам dar даже как-то не пробовал ставить — как говорится вполне хватает tar+gz ))), тем более что мой сервак для разработки достаточно слабый, а места вполне хватает, поэтому мне выгодней использовать менее ресурсоемкие подходы в плане CPU/RAM нежели большее сжатие
                0
                Я медиа-папки тоже бекаплю отдельно, конечно, но всё равно home-директории домашних в ужатом виде до 70ГБ доходят. У каждого %) И их на куски особо не поделишь, так как бардак.

                Но при восстановлении из бекапа есть ещё одно преимущество dar'а: ему не обязательно пролистывать весь бекап, чтобы вытащить нужный файл (а tar'у c gz обязательно). Единственное что, листинг действительно гигантского архива может минуты занимать. Но это на атоме и архивах порядка 50-100ГБ.

                В общем, тут с tar'ом была бы тоска совсем.
                  0
                  В сторону dar не посмотрел т.к. банально был о нем не в курсе =) Погляжу что это такое повнимательней, т.к. проблема с большими архивами в некоторых случаях актуальна, хотя и не критична.
                  Выбирал только между банальными rsync, tar и даже cp+gzip. Oстановился на tar по субъективным причинам.
            0
            К tar 'у все же большинство привыкли. И в большинстве дистров он идет изкоробки.
              +1
              В большинстве дистрибутивов и dar идёт изкоропки. Просто о нём мало кто знает. Да и параметры у него сложноваты.
            +9
            Велосипедостроители. Используйте то что уже написано за вас. rsnapshot(для маленьких), bacula(для больших)
              +1
              Я тут давно rsnapshot пользую. Нарисовал скрипт автобекапа при подключении внешнего винта с ext3 разделом.

              Кому интересно, могут пройти и почитать: blog.lyalyuev.pp.ua/2012/01/12/avtomaticheskiy-bekap-pri-podklyucheni/
                0
                Любопытно, возьму правило на вооружение, полезная штука.
                  +2
                  Как думаете, стоит рерайтить и расширить на Хабре это дело? :)
                    +3
                    А почему бы и нет?
                –1
                Грубовато малость, не находите?
                Как писалось выше:
                bash: Бэкап без лишнего ПО
                … с использованием минимума стороннего ПО...

                В моем случае дополнительно установленное ПО — sendxmpp и пара пакетов из самбы, которые у меня и так установлены. Мотивы… зачем мне ставить и настраивать бакулу, если мне достаточно возможностей tar`а? К слову — бакулу устанавливал, попользовал, удалил, написал этот скрипт.
                Ну и, пардон, повторюсь, выбирал только между банальными rsync (rsnapshot) и tar. Oстановился на tar по субъективным причинам.

                В любом случае спасибо за альтернативы. В топике я не предлагал вариантов, хорошо, что они обозначаются в обсуждении.
                  –1
                  Вот я когда полтора года назад свой скрипт писать собирался тоже думал, что надо по-серьёзному, взять готовое, проверенное решение :)
                  Ага, щаз! Оказалось, что проще самому накатать сто строчек на баше, чем даже выбрать из существующих систем. И в итоге всё своё, родное, что надо умеет, что не надо глаза не мозолит.
                    0
                    Этим и прекрасен Линукс :)
                –1
                backup-manager
                  +5
                  Почему используются такие «нечитаемые» имена переменных? Экономите память?: )
                  TN — TASKNAME
                  SRCD — SouRCe Directory
                  TGTD — TarGeT Directory

                  Называй как есть, TASKNAME/TASK_NAME, будет удобнее и последователям, и самому себе, когда откроешь код через полгодика: )
                    0
                    Учту, спасибо
                      –3
                      Зачем? Не менее понятные переменные TASK, SRCDIR, TGTDIR — и меньше писать, и вполне понятно.
                        –1
                        развивает культуру кода, хотя бы
                      0
                      Поскольку это всего лишь выложил вариант и я не настаиваю на его исключительности, любые предложения и критика уместны =) Они помогают учиться дальше. + Кого-то они могут устроить больше, чем предложенные мной.
                      Я далеко не гуру и не настаиваю на таком статусе, я всего-лишь учусь =)… учусь скриптить для своих нужд, и делюсь наработками с теми, кому они могут пригодиться. А также расчитываю довести до ума какие-то моменты, о которых сразу не подумал.
                        +4
                        Посмотрите в сторону функций в bash. Если написать функцию для логирования, то это существенно сократит ваш скрипт и приведёт его к более удобочитаемому виду.

                        И кстати, можно ещё подсократить скрипт, выкинув оттуда часть if'ов. А проверку осуществлять в таком духе:
                        command && log «command success» || error_log «command failed»
                        где log и error_log функции обрабатывающие просто лог и ситуацию с ошибками.
                        Тут, правда, есть подводный камень, что если функция log завершится с ошибкой, то error_log всё равно выполнится. Но может оно и правильно? (:

                        И, судя по закомментированным docs-weekly и docs-daily, у вас ещё имеется пара аналогичных скриптов для docs-weekly и docs-daily. Можно эту переменную передавать через параметры запуска $1,$2 и т.д. или даже парсить их getopt'ом (опционально), прикрутить проверку корректности, проверку от дурака, и… впрочем что-то меня не туда понесло.
                          0
                          > Можно эту переменную передавать через параметры запуска $1,$2
                          А можно сделать несколько симлинков и проверять, чему равен $(basename "$0")
                          Ну это уже так…
                          0
                          для бэкапа файловой системы виртуальных машин я остановился на rdiff-backup
                          вот такой скриптик запускается по крону на родительском хосте

                          #!/bin/sh
                          # local dom0 host
                          HOST=zzzzzzz
                          # volume group
                          VG=vg00
                          # file containing volume names
                          LV=$1
                          # PID file
                          PID=/tmp/rdiff-backup-lv.pid
                          # remote path to backup server (requires SSH-RSA auth)
                          BACKUP_PATH=remote@xxxx.xxxx.com::/opt/remote-backups
                          # period to keep old backups 
                          KEEP_BACKUPS_FOR=2W
                          
                          echo "Backing up $LV from $VG"
                          SNAP=snap_$LV
                          
                          if [ -f $PID ]; then
                          	if [ `ps ax | grep \`cat $PID\`| grep $0 | wc -l` -eq 0 ]; then
                          		echo "Previous run didn't end well; removing process $PID" 
                          		rm $PID
                          	else
                          		echo "Backup still runs, can't start another instance" 
                          		exit 1
                          	fi
                          fi	
                          	echo $$ >$PID
                          	(	
                          		if [ -e /dev/$VG/$SNAP ]; then
                          			umount /mnt/snap
                          			lvremove -f /dev/$VG/$SNAP	
                          	  	fi	
                          		if ! lvcreate --size 1G --snapshot --name $SNAP /dev/$VG/$LV; then
                          			exit 1
                          		fi
                          
                          		if ! mount -o ro /dev/$VG/$SNAP /mnt/snap; then
                          			lvremove -f /dev/$VG/$SNAP
                          			exit 1
                          		fi
                          	) 1>&2 </dev/null || exit 1
                          
                          	if [ -f /mnt/snap/exclude-from-backup ]; then
                          		rm -f /tmp/exclude-from-backup
                          		for l in `cat /mnt/snap/exclude-from-backup`; do echo /mnt/snap$l >> /tmp/exclude-from-backup; done
                          		OPTIONS="--exclude-filelist /tmp/exclude-from-backup"
                          	else
                          		OPTIONS="--exclude-device-files  --exclude-sockets"
                          	fi
                          
                          	if [ ! -d /mnt/snap/etc ]; then
                          		echo "Image doesn't seem to be mounted properly"
                          		umount /mnt/snap
                          		exit 1
                          	fi
                          	
                          	rdiff-backup $OPTIONS /mnt/snap $BACKUP_PATH/$HOST-$LV
                          	rdiff-backup --force --remove-older-than $KEEP_BACKUPS_FOR $BACKUP_PATH/$HOST-$LV
                          
                          	(
                          		umount /mnt/snap
                          		lvdisplay /dev/$VG/$SNAP
                          		lvremove -f /dev/$VG/$SNAP
                          		rm $PID
                          	) 1>&2 </dev/null
                          
                          
                            0
                            и ещё одна нелишняя деталь:
                            для нагиоса поставил этот плагин, если бэкап какой-то машины не делается сутки — звенит звонок
                              +1
                              Эх. Вот рассчитан данный скрипт на небольшой объём данных. В этих целях откройте для себя duplicity (который ещё и шифровать умеет для передачи по каналам типа ftp и хранения в S3)
                                0
                                И rdiff-backup от того же автора (использую для бекапа конифигов системы, а duplicity для икрементных бекапов больших файлов).
                                +3
                                git?
                                  0
                                  Tcccc!
                                  0
                                  Спасибо за обьяснение про $IFS и пути с пробелами! Недавно хотел автоматизировать один процесс и застрял из-за пробела в имени директории…
                                    0
                                    из за таких как вы…
                                      0
                                      Ещё вариант простого bash-скрипта для создания бэкапов:

                                      #!/bin/bash
                                      
                                      if [ $UID -ne 0 ] ; then
                                          echo "Error: you must be root" >&2
                                          exit 1
                                      fi
                                      
                                      ARCHIVE="/tmp/etc.$(hostname).$(date '+%d%m%Y').gz"
                                      
                                      grep -e "^#F/" ${0} | sed 's/#F//' | while read FNAME ; do
                                      	if [ -d ${FNAME} ] ; then
                                      		find ${FNAME} -xtype f
                                      	elif [ -f ${FNAME} ] ; then
                                      		echo ${FNAME}
                                      	else
                                      		echo "Warning: file ${FNAME} no found" >&2
                                      	fi
                                      done | cpio -o -H tar --quiet | gzip -9c >${ARCHIVE}
                                      
                                      s3cmd --no-progress put ${ARCHIVE} s3://bucket/backup/
                                      rm -f ${ARCHIVE}
                                       
                                      #F/usr/bin/etc.backup
                                       
                                      #F/etc/ssh/sshd_config
                                      #F/etc/network/if-pre-up.d/iptables
                                      #F/etc/iptables.rules
                                      


                                      Список файлов/катлогов для архивирования указывается в самом скрипте: #F/path
                                      В данном случае готовый архив отправляется на amazon s3
                                        0
                                        Под окнами, во многих случаях, пользуюсь этой программкой. Мною писана спецом дабы уйти от написания скриптов копирования. Фишка программы в том что в ключах можно использовать несколько масок на ключ. А сами ключи разделены на ключи для папок и для файлов. Есть и другие навороты. Если кому интересно пользуйтесь, програма халявная. Если будут интересные предложения функционал можно дальше расширить (хотя того что там уже есть, на мой взгляд, уже вполне достаточно).

                                        Only users with full accounts can post comments. Log in, please.