nixp.ru v3.0

22 января 2017,
воскресенье,
04:46:59 MSK

DevOps с компанией «Флант»
anonymous написал 13 марта 2006 года в 12:40 (361 просмотр) Ведет себя неопределенно; открыл 1814 темы в форуме, оставил 5575 комментариев на сайте.

Хочу наладить простое резервное копирование информации с помощью cron, tar и gunzip.

Создал скрипт, залил в крон, все нормально.

#!/bin/bash

tar -czf archivename.tar.gz /path/to/dir

Но мне нужно чтобы архив создавался за определенный период времени, например:

13.10.2006 — Создан архив от 13.10

14.10.2006 — Создан архив от 14.10

15.10.2006 — Создан архив от 15.10

16.10.2006 — Удален архив от 13.10; Создан архив от 16.10.

Логику написания данного скрипта понимаю, но познания shell достаточно скромные.

Если у кого-нибудь есть похожий скрипт, пожалуйста, приведите пример.

Dr. Evil

а просто поместить твой скрипт:

#!/bin/bash  
tar -czf archivename.tar.gz /path/to/dir

в папку /etc/cron.hourly не проще?

правда, я не помню, будет ли cron как-то каждый новый файл называть по-новому

anonymous

Создавать каждый раз новое имя файла — не проблема.

Я хочу получать не более трех файлов с архивами.

Dr. Evil

брррр…

не понял.

тебе надо, чтобы архивов (т.е. твоих бэкапов) было не более трех?

anonymous

Именно.

Неболее трех (пяти, десяти, любое число).

Если делать просто архивирование, допустим ежедневное для mysql, то таких архивов будет 365 штук в году.

Мне же нужно только за последние три дня или неделю.

Dr. Evil

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

anonymous

1. Периодичность — 1 бекап \ сутки

2. Хочу иметь 7 бекапов в неделю.

3. Хочу иметь бекапы только за неделю (7 дней).

Dr. Evil

получается так, что каждый день у тебя делается бэкап. в понедельник, вторник, …..

в воскреченье будет седьмой, а когда наступит очередной понедельник, ты хочешь, чтобы у тебя сделался бэкап, а сделанный в предыдущий понедельник удалился. так?

anonymous

Именно так

Dr. Evil

вывод date давай

мда…

anonymous

Я бытаюсь написать скрипт,

познания шелл программирования минимальные.

Думал уже что-то готовое есть.

Напишу — поделюсь.

Dr. Evil

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

давай вывод date, будет тебе скрипт;)

anonymous

$date Пнд Мар 13 16:10:35 EET 2006

$date —help

Использование: date [КЛЮЧ]… [+ФОРМАТ]

или: date [-u|--utc|--universal] [ММДДччмм[[ВВ]ГГ][.сс]]

Выводит текущее время в заданном ФОРМАТЕ, или устанавливает системное время.

-d, —date=СТРОКА показать не текущее время, а время, описанное

заданной СТРОКОЙ

-f, —file=ФАЙЛ соответствует применению —date для каждой

строки ФАЙЛА

-IСПЕЦ, —iso-8601[=СПЕЦ] вывести дату/время в виде, соответствующем

стандарту ISO-8601.

СПЕЦ=`date' для получения только даты,

`hours’, `minutes' или `seconds' для получения

даты и времени с указанной точностью.

—iso-8601 без СПЕЦ эквивалентно `date’.

-r, —reference=FILE display the last modification time of FILE

-R, —rfc-2822 output RFC-2822 compliant date string

-s, —set=STRING set time described by STRING

-u, —utc, —universal print or set Coordinated Universal Time

—help показать эту справку и выйти

—version показать информацию о версии и выйти

ФОРМАТ управляет выводом. Единственный ключ, допустимый для второй

формы, задает координированное универсальное время. Воспринимаются

следующие последовательности:

%% знак %

%a местное сокращенное название дня недели (пон..вск)

%A местное полное название дня недели, переменной длины (понедельник..воскресенье)

%b местное сокращенное название месяца (янв..дек)

%B местное полное название месяца, переменной длины (январь..декабрь)

%c местное время и дата (Срд Фев 16 16:28:09 MSK 2000)

%C век (год, деленный на 100 и округленный до целого) [00-99]

%d день месяца (01..31)

%D дата (мм/дд/гг)

%e день месяца, пробелы вместо нулей ( 1..31)

%F эквивалентно %Y-%m-%d

%g двузначный год, соответствующий номеру недели %V

%G четырехзначный год, соответствующий номеру недели %V

%h то же, что и %b

%H час (00..23)

%I час (01..12)

%j номер дня в году (001..366)

%k час ( 0..23)

%l час ( 1..12)

%m месяц (01..12)

%M минуты (00..59)

%n новая строка

%N наносекунды (000000000..999999999)

%p местный индикатор AM или PM заглавными буквами (пусто во многих локалях)

%P местный индикатор AM или PM строчными буквами (пусто во многих локалях)

%r время, 12-часовой формат (чч:мм:сс [AP]M)

%R время, 24-часовой формат (чч:мм)

%s число секунд, истекших с `00:00:00 1970-01-01 UTC' (расширение GNU)

%S секунды (00..60); 60-ая нужна для високосной секунды

%t горизонтальная табуляция

%T время, 24-часовой формат (чч:мм:сс)

%u день недели (1..7); 1 обозначает понедельник

%U номер недели в году, если первый день недели — воскресенье (00..53)

%V номер недели в году, если первый день недели — понедельник (01..52)

%w день недели (0..6), 0 означает воскресенье

%W номер недели в году, если первый день недели — понедельник (00..53)

%x местное представление даты (дд/мм/гг)

%X местное представление времени (%H:%M:%S)

%y последние две цифры года (00..99)

%Y год (1970…)

%z RFC-2822 style numeric timezone (-0500) (a nonstandard extension)

%Z time zone (e.g., EDT), or nothing if no time zone is determinable

By default, date pads numeric fields with zeroes. GNU date recognizes

the following modifiers between `%' and a numeric directive.

`-' (hyphen) do not pad the field

`_' (underscore) pad the field with spaces

Об ошибках сообщайте по адресу .

Genie
1. Периодичность — 1 бекап \ сутки

2. Хочу иметь 7 бекапов в неделю.

3. Хочу иметь бекапы только за неделю (7 дней).

пошевелить мозгами немного и поэкспериментировать с ключами у date.

может 'date +%d%m%y' будет что надо?

хотя для сортировки я бы наоборот расположил.. ;)

в общем, читать внимательно:

man date

man tar (как оному рассказать, что надо паковать только файлы позднее заданной (которую можно получить по команде date))

man gzip или bzip2 (впрочем, внимательное прочтение мана по tar про них упомянет)

и что ещё? описание по shell.

man bash

только это не учебник…

кроме того, есть opennet.ru/ — где много чего интересного есть по теме

Dr. Evil

тогда попробуй так: в /etc/cron.daily запихивай скрипт с таким содержанием:

#!/bin/sh

ls /path/to/dir |grep -v `date +%a%d%m%y`| grep `date +%a`| xargs rm -f

tar -czf «archiv`date +%a%d%m%y`».tar.gz /path/to/dir

fly4life
Dr._Evil
тогда попробуй так: в /etc/cron.daily запихивай скрипт с таким содержанием:

#!/bin/sh

ls /path/to/dir |grep -v `date +%a%d%m%y`| grep `date +%a`| xargs rm -f

tar -czf «archiv`date +%a%d%m%y`».tar.gz /path/to/dir

Тут в первой строчке конструкция: «grep -v `date +%a%d%m%y`|» — всё-таки лишняя.

rgo

а я бы, сделал всё чуть проще…

#!/bin/bash
for (( i=6; i>0; i-- )); do
    mv archive.tar.gz.$i archive.tar.gz.$((i+1))
mv archive.tar.gz archive.tar.gz.1
tar -zcf file.tar.gz /path/to/dir

А если уж заморачиваться с датами, то удобнее пользоваться find.

Dr. Evil

да, точно.

черт. файла, созданного в этот день, еще нет…

:(

Genie
а я бы, сделал всё чуть проще…

а если подумать, то есть такая хрень, как logrotate, которая делает тоже самое, только несколько более удобно и стабильно ;)

fly4life
Dr._Evil
да, точно.

черт. файла, созданного в этот день, еще нет…

:(

Вот именно, что даже если и есть, то второй строчкой он всё равно будет создан заново. Поэтому удалить его перед повторным созданием не помешает ;).

fly4life
rgo
а я бы, сделал всё чуть проще…

#!/bin/bash
for (( i=6; i>0; i-- )); do
    mv archive.tar.gz.$i archive.tar.gz.$((i+1))
mv archive.tar.gz archive.tar.gz.1
tar -zcf file.tar.gz /path/to/dir

Фига себе, проще.. ;)

Проще тогда уж действительно logrotate, как сказал Genie. Но откуда ж знать, есть ли он у автора темы, настроен ли…

Скрипт Эвила в этом плане универсальнее. С путями только быть повнимательнее ;). Потому как имя /path/to/dir после 'ls' НЕ должно быть равым имени каталога /path/to/dir, архив которого делается.

rgo
А если уж заморачиваться с датами, то удобнее пользоваться find.

В данной задаче не удобней.

Genie
fly4life
В данной задаче не удобней.

man tar читамши?

оно само умеет. ;)

fly4life
Genie
man tar читамши?

оно само умеет. ;)

Эм… find и tar, насколько я понял, это разные утилиты? И даже из разных пакетов, да? ;) Это хорошо, что tar умеет find (я, признаюсь, этого в man и вправду не нашёл. Хотя и не особо-то искал ;)) — универсальный всё-таки архиватор ;). Однако ни я, ни rgo про него ни словом не обмолвились.

Можно я ещё раз повторю:

rgo>> А если уж заморачиваться с датами, то удобнее пользоваться find

fly4life> В данной задаче не удобней.

Просто, если с find действительно удобней (хоть с помощью tar, хоть — отдельной утилиты), то надо бы пример, чтоб убедиться в этом. А пока я считаю, что не удобней.

Genie
fly4life
Можно я ещё раз повторю:

rgo>> А если уж заморачиваться с датами, то удобнее пользоваться find

fly4life> В данной задаче не удобней.

Просто, если с find действительно удобней (хоть с помощью tar, хоть — отдельной утилиты), то надо бы пример, чтоб убедиться в этом. А пока я считаю, что не удобней.

ага. только если мы собираемся архивировать, то это будем делать tar-ои. так?

далее. tar умеет искать файлы, которые изменялись после определённой даты

и не надо для этого брать find. про это я и говорил ;)

fly4life
Genie
ага. только если мы собираемся архивировать, то это будем делать tar-ои. так?

далее. tar умеет искать файлы, которые изменялись после определённой даты

и не надо для этого брать find. про это я и говорил ;)

Ах, ну ежели обо всяких инкрементальных бекапах речь вести… Только find, о котором говорил rgo и чему возразил я, тут совсем ни при чём.

rgo

насчёт find. Вот эта строчка, как я понял, должна удалить устаревшие бекапы:

ls /path/to/dir |grep -v `date +%a%d%m%y`| grep `date +%a`| xargs rm -f

Так? Точнее один файл недельной давности. Вот как это делается с find:

Или нет, чего-то я на неё повнимательнее посмотрел — теперь вообще нифига не понимаю.

Но если всё-таки имелось в виду удалить бекап 7-ми дневной давности (и случайно оставшиеся с доисторических времён), то:

find /where/backups/ -atime 7 | xargs rm -f

Единственная проблема — если предположить что последующая tar -zcf работает мгновенно, то будет вероятность оставить архивы за 8 дней, но это ведь вряд ли и не страшно, т.к. назавтра всё исправим.

Потому как имя /path/to/dir после 'ls' НЕ должно быть равым имени каталога /path/to/dir, архив которого делается.

этого заявления я просто не понял: как «/path/to/dir» может быть не равным «/path/to/dir», пускай и даже после 'ls’.

На всякий случай поясню, не знаю что, но поясню, мой скрипт будет создавать/удалять/переименовывать архивы в текущей директории, а /path/to/dir с ней соотностится только в том, что не стоит архивы хранить в дереве /path/to/dir.

А насчёт logrotate — так с него идею и содрал.

rgo
Единственная проблема — если предположить что последующая tar -zcf работает мгновенно, то будет вероятность оставить архивы за 8 дней, но это ведь вряд ли и не страшно, т.к. назавтра всё исправим.

это я немного не то сказал. Суть в том, что с датами всё-таки придётся повозиться отдельно. Или иметь с некоторой вероятностью 7 или 8 архивов.

fly4life
rgo
насчёт find. Вот эта строчка, как я понял, должна удалить устаревшие бекапы:
ls /path/to/dir |grep -v `date +%a%d%m%y`| grep `date +%a`| xargs rm -f

Так? Точнее один файл недельной давности.

Часть этой строчки всё-таки лишняя (я писал выше, какая именно), но не суть..

В этой строке удаляется архив, в имени которого присутствует название текущего дня недели (параметр %a у date). Так что это не совсем «файл недельной давности». Т.е., он, конечно же, будет недельной давности, но только при соблюдении условия, что cron отрабатывал строго каждый день.

rgo
Вот как это делается с find:

Или нет, чего-то я на неё повнимательнее посмотрел — теперь вообще нифига не понимаю.

Но если всё-таки имелось в виду удалить бекап 7-ми дневной давности (и случайно оставшиеся с доисторических времён), то:

find /where/backups/ -atime 7 | xargs rm -f

При таком правиле, если твой скрипт выполнится после, например, двухнедельного простоя машины (или cron’а), то он удалит все бекапы.

rgo
Единственная проблема — если предположить что последующая tar -zcf работает мгновенно, то будет вероятность оставить архивы за 8 дней, но это ведь вряд ли и не страшно, т.к. назавтра всё исправим.

Если даже и мгновенно, то всяко после выполнения первой команды (в которой делается rm). Так что тут волноваться нечего ;).

rgo
этого заявления я просто не понял: как «/path/to/dir» может быть не равным «/path/to/dir», пускай и даже после 'ls’.

Так всё просто ж ;). Вот смотри. Приведу для наглядности скрипт Эвила (в его первой строчке я удалил ненужную конструкцию, о которой говорил в поправке к скрипту):

ls /path/to/dir | grep `date +%a`| xargs rm -f
tar -czf "archiv`date +%a%d%m%y`".tar.gz /path/to/dir

В первой строке делается листинг директории с готовыми архивами. Во-второй указана директория, архив которой делается. Они не должны быть равными. Т.е. следовало бы в скрипте написать так:

ls /path/to/dir/with/backups | grep `date +%a`| xargs rm -f
tar -czf /path/to/dir/with/backups/archive-`date +%a%d%m%y`.tar.gz /path/to/dir/with/data/for/archive

Теперь по понятней? ;)

rgo
На всякий случай поясню, не знаю что, но поясню, мой скрипт будет создавать/удалять/переименовывать архивы в текущей директории, а /path/to/dir с ней соотностится только в том, что не стоит архивы хранить в дереве /path/to/dir.

Я именно про это <font size=«-2»><font color=«grey»>[не стоит архивы хранить в дереве /path/to/dir]</font></font> и говорил ;). А говоришь, что не понял ;). А что делает твой скрипт — всем и так ясно. Догадались же, что на logrotate похоже ;)

rgo
А насчёт logrotate — так с него идею и содрал.

;)

rgo
Теперь по понятней? ;)

ага.

При таком правиле, если твой скрипт выполнится после, например, двухнедельного простоя машины (или cron’а), то он удалит все бекапы.

угу, это есть баг. :(

Но теперь если отлистнуть на страницу назад и посмотреть что же собственно было надо, то выясниться что число 7, бралось для примера. На самом деле может быть надо 3 или 9, автор топика ещё не решил.

А против этого будут возражения:

ls | nl | tail -n 1 | (
    read n rest
    if (( n>6 )); then
        ls -tr | head -n $((7-n)) | xargs rm -f
    fi)


?

Genie
А против этого будут возражения?

ахха. :))

1) найдётся ещё какой чукча, что файлы бакапа с «.» именовать додумается.. :)

2) может так:

count=`ls -A shell*pattern | wc -l`

if ((n>6)); then

ls -Atr shell*pattern | tail -n $((n-7)) | xargs -r rm -f

fi

3) однако, и тут для чукчи есть где разгуляться: пробел в имени и…

Dr. Evil

как не решил?

он в самом начале написал, что

1. Периодичность — 1 бекап \ сутки

2. Хочу иметь 7 бекапов в неделю.

3. Хочу иметь бекапы только за неделю (7 дней).

Longobard
Владимир
Логику написания данного скрипта понимаю, но познания shell достаточно скромные.

Если у кого-нибудь есть похожий скрипт, пожалуйста, приведите пример.

У меня есть, только для бэкапа mysql баз. И удаляются базы за прошлый месяц, а не за неделю. Так что подправишь то, что нужно :)

#!/bin/bash
#директория, куда будет сгенерен дамп
DUMP_STORAGE="/home/http/foto/mysql-dump"
#рабочая директория мускуля
MYSQL_ROOT="/var/lib/mysql"
#пасс на доступ к базе (root@localhost)
PASS="xxxxx"
#шаблон имени создаваемого дампа
FNAME="`date +%d.%m.%Y-%H.%M`-mysqldump.tar.bz2"
#строка для schedtool (если вы хотите чтобы проц грузился меньше,
#и если у вас установлен schedtool и нужные патчики к ядру :)
SHED_STR="/usr/bin/schedtool -B -e "
echo "Check and repair"
$SHED_STR /usr/bin/mysqlrepair --all-databases --auto-repair --password=$PASS
cd $DUMP_STORAGE
list=`ls $MYSQL_ROOT`
for i in $list;
do
    echo "Dumping database $i"
    $SHED_STR /usr/bin/mysqldump -c --password=$PASS $i > $i.sql
    /bin/ls -lh $i.sql
    echo "`wc -l $i.sql`"
done
ndate=`date +%_m`
let "rem=$ndate-1"
echo "Creating $DUMP_STORAGE/$FNAME"
$SHED_STR /bin/tar cvjf $FNAME *.sql
echo $FNAME created succesfully:
/bin/ls -lh $FNAME
echo "Clearing temporary .sql files"
$SHED_STR  /bin/rm *.sql
echo "Cleared"
echo "Removing $DUMP_STORAGE/??.?$rem.*.tar.bz2"
/bin/rm $DUMP_STORAGE/??.?$rem.*.tar.bz2 2> /dev/null
rgo
2) может так:

угу. так приятнее. про wc я как-то забыл.

3) однако, и тут для чукчи есть где разгуляться: пробел в имени и…

ну, если мы расчитываем на чукчу, засовывающего всё что ни попадя с форумов в cron, не разбираясь, что собственно и как делается… То я думаю следует срочно изменить линию поведения и в один голос твердить что logrotate это его главный инструмент, а man logrotate гораздо круче форума.

Но я тут, на досуге придумал другую штуку:

name=archive-$(( (`date +%s` / (3600 * 24)) % N )).tar.bz2
rm -f $name
tar -zcf $name /dir/to/backup

N — это количество живых архивов

ecobeingecobeing.ru
Экология и вегетарианство на благо всем живым существам Планеты.