Лучший способ архивировать и архивировать файлы, отвечающие определенным критериям имен? - PullRequest
0 голосов
/ 10 мая 2018

Я пишу сценарий оболочки на машине Linux для запуска через crontab, который предназначен для перемещения всех файлов старше текущего дня в новую папку, а затем tar и заархивирует всю папку. Похоже, простая задача, но по какой-то причине я сталкиваюсь с различными препятствиями. Я новичок в этом и самоучка, поэтому любая помощь или перенаправление будет принята с благодарностью.

Конкретные критерии для каких файлов архивировать:

  • Все файлы журнала находятся в /home/tech/logs/, а все файлы в формате PDF - /home/tech/logs/pdf

  • Все файлы старше одного дня, как указано в имени файла (имя файла не включает $CURRENT_DATE)

  • Все файлы должны быть *.log или *.pdf (т.е. не архивировать файлы, которые не включают $CURRENT_DATE, если это не файл журнала или файл PDF.

Особенности форматирования имени файла:

Все имена файлов журнала находятся в home/tech/logs в формате NAME 00_20180510.log, а все файлы pdf находятся в подкаталоге «pdf» (home/tech/logs/pdf) с форматом NAME 00_20180510_00000000.pdf («20180510» будет использоваться всякий раз, когда файл был создан, и 0 будет любым числом). Мне нужно использовать имя, а не метаданные файла для даты создания, и все файлы (pdf / log), чье имя не включает текущую дату, являются «старыми». Я также не могу просто переместить все файлы, которые не содержат $CURRENT_DATE в имени, потому что для этого потребуются файлы не *.pdf или *.log.

Прямо сейчас скрипт создает новую папку с новым подкаталогом pdf для старых файлов (mkdir -p /home/tech/logs/$ARCHIVE_NAME/pdf). Затем я хочу переместить старые журналы в $ARCHIVE_NAME и переместить все старые PDF-файлы из исходного подкаталога PDF в $ARCHIVE_NAME/pdf.

Текущий код:

find /home/tech/logs -maxdepth 1 -name ( "*[^$CURRENT_DATE].log" "*.log" ) -exec mv -t "$ARCHIVE_NAME" '{}' ';'

find /home/tech/logs/pdf -maxdepth 1 -name ( "*[^$CURRENT_DATE]*.pdf" "*.pdf" ) -exec mv -t "$ARCHIVE_NAME/pdf" '{}' ';'

Это не сработало, потому что обрабатывает числа в $CURRENT_DATE как список чисел, которые нужно исключить, а не как буквальную строку.

Я рассмотрел только использование опций исключения tar, например:

tar -cvzPf "$ARCHIVE_NAME.tgz" --directory /home/tech/logs --exclude="$CURRENT_DATE" --no-unquote --recursion --remove-files --files-from="/home/tech/logs/"

Но а) он не работает, и б) теоретически он включал бы все файлы, которые не были *.pdf или *.log файлами, что было бы проблемой.

Я это слишком усложняю? Есть ли лучший способ сделать это?

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Опираясь на ответ @ tom-fenech, оптимизирован, чтобы избежать многих mv вызовов:

find /home/tech/logs -maxdepth 1 -name '*.log' -not -name "*_${CURRENT_DATE?}.log" | \
  xargs mv -t "${ARCHIVE_NAME?}"

Интересной особенностью обработки файлов через каналы является возможность фильтровать их с помощью дополнительных инструментов (иначе называемых grep :), которые могут (возможно) стать более читабельными, т. Е. ->

find /home/tech/logs -maxdepth 1 -name '*.log' | fgrep -v "_${CURRENT_DATE?}" | \
  xargs mv -t "${ARCHIVE_NAME?}"

Затем аналогично для pdf, BTW вы можете "пробный прогон" выше, просто заменив mv на echo mv.

- jjo

0 голосов
/ 10 мая 2018

Я бы пошел на это, используя расширенные возможности глобуса bash, которые позволяют вам отрицать шаблон:

#!/bin/bash

shopt -s extglob

mv /home/tech/logs/*!("$CURRENT_DATE")*.log "$ARCHIVE_NAME"
mv /home/tech/logs/pdf/*!("$CURRENT_DATE")*.pdf "$ARCHIVE_NAME"/pdf

При включенном extglob, !(pattern) распространяется на все, что не соответствует шаблону (или списку шаблонов, разделенных трубами).

Использование find также должно быть возможным:

find /home/tech/logs -name '*.log' -not -name "*$CURRENT_DATE*" -exec mv -t "$ARCHIVE_NAME" {} +
...