Команда Bash для ежедневного архивирования файлов в зависимости от даты добавления

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

Некоторые ограничения:

  • Загрузка с сервера Windows на сервер Ubuntu.

  • Невозможность удаления файлов на удаленном сервере.

  • Требовать дату добавления в локальный каталог, а не дату создания файла.

  • У меня работает дедупликация на этапе скачивания; однако (используя ncftp) проверка включает сравнение удаленного и локального каталогов. Стратегия заключается в том, чтобы каждый день создавать новую папку, загружать в нее файлы, а затем запускать ее где-то после полуночи. Проблема возникает в том, что первая запланированная загрузка в новый день захватит ВСЕ файлы на удаленном сервере, потому что новая локальная папка пуста.

Из-за ограничений я решил просто архивировать файлы на основе «даты добавления» в центральную папку. Это очень хорошо работает на Mac, потому что HFS+ хранит расширенные метаданные, такие как дата создания и дата добавления. Поэтому я могу объединить команду tar с чем-то вроде следующего:

 mdls -name kMDItemFSName -name kMDItemDateAdded -raw *.xml | \ 
 xargs -0 -I {} echo {} | \ 
 sed 'N;s/\n/ /' | \

но аналога под линуксом похоже нет (по крайней мере не с EXT4, о котором я знаю).

Я открыт для любой формы решения, чтобы обойти дублирование файлов на следующий день. Конечным результатом должен быть каталог архивов, полный файлов tar.gz, который выглядит примерно так:

files_$(date +"%Y-%m-%d").tar.gz

person FocusedEnergy    schedule 27.05.2016    source источник


Ответы (1)


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

Вы можете получить эту информацию с помощью команды stat:

stat <filename>

который вернет следующее (вместе с другой информацией, связанной с файлом, не показанной):

Access: 2016-05-28 20:35:03.153214170 -0400
Modify: 2016-05-28 20:34:59.456122913 -0400
Change: 2016-05-29 01:39:52.070336376 -0400

Этот вывод из файла, который я скопировал с помощью cp -p во время, показанное как «изменение».

Вы можете получить только время изменения, вызвав stat в указанном формате:

stat -c '%z' <filename>
2016-05-29 01:39:56.037433640 -0400

или с большой буквы Z для этого времени в секундах с начала эпохи. Вы можете комбинировать это с командой даты, чтобы вытащить только дату (или использовать grep и т. д.)

date -d "`stat -c '%z' <filename>" -I
2016-05-29

Команду find можно использовать для поиска файлов по временным рамкам, в данном случае с использованием флагов -cmin «измененные минуты», -mmin «измененные минуты» или, что маловероятно, -amin «доступные минуты». Последовательность команд для получения минут с полуночи немного уродлива, но она работает.

Мы должны найти аргумент «минуты с момента последнего изменения файла» (или изменения, если этот критерий работает). Итак, сначала вы должны посчитать минуты с полуночи, а затем запустить find.

min_since_mid=$(echo $(( $(date +%s) - $(date -d "(date -I) 0" +%s) )) / 60 | bc)

Немного развернуть это:

  • $(date +%s) == секунд с начала эпохи до «сейчас»
  • "(date -I) 0" == текущая дата в формате "ГГГГ-ММ-ДД 0", где 0 указывает на 0 секунд в день
  • $(date -d "(date -I 0" +%s)) == секунд от эпохи до сегодняшней полуночи
  • Затем мы (эффективно) повторяем ( $now - $midnight ) / 60 в bc, чтобы преобразовать результаты в минуты.

Вызов поиска передается в минутах, прошедших с полуночи, с начальным «-», указывающим до X минут назад. Знак «+» указывает на X минут или более назад.

find /path/to/base/folder -cmin -"$min_since_mid"

Фактический ответ

Наконец, чтобы создать tgz-архив файлов в данном каталоге (и подкаталогах), которые были изменены с полуночи сегодня, используйте эти две команды:

min_since_mid=$(echo $(( $(date +%s) - $(date -d "(date -I) 0" +%s) )) / 60 | bc)

find /path/to/base/folder -cmin -"${min_since_mid:-0}" -print0 -exec tar czvf /path/to/new/tarball.tgz {} +

Аргумент -print0 для поиска сообщает, что файлы должны быть разделены нулевой строкой, что, среди прочего, предотвратит проблемы с пробелами в именах.

Единственное, в чем я не уверен, так это в том, что вы должны использовать измененное время (-cmin), измененное время (-mmin) или время доступа (-amin). Взгляните на свои файлы резервных копий и посмотрите, какое поле точно отражает дату/время резервной копии - я бы подумал, что изменилось время, но я не уверен.

Обновление: изменено -"$min_since_mid" на -"${min_since_mid:-0}", так что если min_since_mid не установлено, вы не получите ошибку с недопустимым аргументом - вы просто не получите никаких результатов. Вы также можете окружить поиск оператором if, чтобы заблокировать вызов, если эта переменная не установлена ​​​​должным образом.

person Argonauts    schedule 29.05.2016
comment
Спасибо, что нашли время написать такой подробный ответ. Я попробовал фактический ответ с соответствующими изменениями, и я продолжаю натыкаться на эту стену: `(standard_in) 1: синтаксическая ошибка; find: неверный аргумент -print0 to -cmin Если я изменю cmin на mmin, он вернет то же самое. Если я уберу первый $ в min_since_mid, первая ошибка исчезнет, ​​но вторая останется. Может у вас есть предложение или, возможно, идея, как обойти эти ошибки? - person FocusedEnergy; 30.05.2016
comment
Вы уверены, что используете -print0 с нулем, а не с буквой O? Какая версия find у вас есть, и есть ли у нее псевдонимы (результаты find --version, type find, which find). Я только что проверил, что код работает нормально на find версии 4.51 (centos 7) и 4.6 (бета-версия Fedora 24). Проверьте, установлено ли значение $min_since_mid. Запустите первую команду; затем echo $min_since_mid, если $min_since_mid пусто, тогда он потерпит неудачу именно так, как вы получаете. - person Argonauts; 30.05.2016
comment
Я должен был сказать «потерпеть неудачу таким же образом»; слово "точно" неверно. Дайте мне знать, что вы узнали, и я постараюсь это исправить. Кроме того, попробуйте запустить только find /path/to/base/folder -cmin -"$min_since_mid" и посмотрите, правильно ли это работает. - person Argonauts; 30.05.2016
comment
Я немного разобрался с командой echo, я думаю, что у моей оболочки были проблемы с вычитанием дат. $min_since_mid возвращает 611, так что это надежно. Если я попробую команду find, она ничего не вернет. Вот подробности находки: версия find 4.4.2, /usr/bin/find, /usr/bin/find - person FocusedEnergy; 30.05.2016
comment
Извините, очень глупая ошибка. Вместо того, чтобы запускать с вычисленными датами в имени моей папки (для автоматического поиска сегодняшней даты), я использовал жестко закодированную дату из моего тестирования прошлой ночью, и это было до полуночи, поэтому, конечно, он ничего не возвращал. Я просто запустил его с правильной ссылкой на папку, и он все нашел и создал файл tgz. Я собираюсь разархивировать его, чтобы проверить, но я думаю, что это решило все мои проблемы. РЕДАКТИРОВАТЬ: только что подтвердил, что все файлы есть в tgz. Большое спасибо за помощь и подробное объяснение. - person FocusedEnergy; 30.05.2016
comment
Просто из любопытства, зафиксировали ли cmin или mmin — или оба — время, когда оно было скопировано? - person Argonauts; 30.05.2016
comment
Я только что попробовал оба и сделал diff mmin.tgz cmin.tgz, и между ними не было никакой разницы. Таким образом, он определенно фиксирует информацию. Тогда мне интересно, если cmin = mmin только на основе создания в локальном каталоге (аналогично дате, добавленной в Mac OSX), а не на фактической дате создания? - person FocusedEnergy; 30.05.2016
comment
Дата создания не обязательна; его можно получить с помощью stat -c '%w', но большинство файловых систем его не хранят. В зависимости от того, как вы копируете/архивируете файлы, измененная отметка времени может обновляться или не обновляться. Измененное должно быть обновлено в любом случае, так что это более безопасный выбор. - person Argonauts; 30.05.2016
comment
еще раз спасибо за разъяснение. Я попробовал %w и, конечно же, он был пуст. Возможно, однажды EXT будет включать расширенные метаданные, как это делает HFS+. - person FocusedEnergy; 30.05.2016