Как написать сценарий оболочки Linux, который удаляет файлы старше X дней, но оставляет первый файл дня по времени модификации? - PullRequest
1 голос
/ 02 марта 2020

Как видно из заголовка, как этот сценарий оболочки может быть реализован. Я знаю, что легко найти файлы и удалить файлы старше, чем v.gr. 29 дней, используя:

find /some_folder/ -name "file_prefix*" -mtime +30 -exec rm {} \;

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

Ответы [ 2 ]

0 голосов
/ 02 марта 2020

Для общих имен файлов

find /some_folder/ -name "file_prefix*" -mtime +30 -printf '%TD %TT %p\n' |
  sort |
  awk '{if ($1==prevdate) print $3; prevdate=$1}' |
  xargs rm

Команда find выведет %TD %TT %p, т.е. дату последней модификации, за которой следует время последней модификации, а затем путь к файлу (папка и имя файла).

Список отсортирован по sort. Из-за структуры дата / время / путь к файлу это будет отсортировано по дате, а затем по времени, так что сначала печатаются самые старые файлы, что важно после.

awk анализирует каждую строку и вызывает {if ($1==prevdate) print $3; prevdate=$1}. Из-за структуры дата / время / путь к файлу дата равна $1, время - $2, а путь к файлу - $3. Это печатает путь к файлу всякий раз, когда дата похожа на ранее проанализированную дату. Таким образом, первый файл дня не распечатывается, поскольку его дата отличается от даты предыдущего дня, и все последующие файлы того же дня печатаются. Обратите внимание, что prevdate изначально не назначен, что примерно эквивалентно пустой строке. Вы можете вызвать это, если найдете его более читабельным:

awk 'BEGIN{prevdate=""} {if ($1==prevdate) print $3; prevdate=$1}'

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

Обработка пробелов

Если ваши имена файлов содержат пробелы, решение может быть слегка скорректировано:

find /some_folder/ -name "file_prefix*" -mtime +30 -printf '%TD %TT %p\n' |
  sort |
  awk '{if ($1==prevdate) print; prevdate=$1}' |
  cut -d ' ' -f3- |
  xargs rm

awk печатает всю строку вместо печати только пути к файлу, затем имя файла извлекается с помощью cut -d ' ' -f3- перед вызовом xargs rm.

Обработка странных имен файлов

Приведенные выше решения не работают с именами файлов, содержащими переводы строки и, возможно, не будут работать с обратными слешами.

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

Однако, если вам нужно обработать все типы имен файлов, приведенная ниже команда выполнит команду rick:

unset prevdate currentdate filepath
find /some_folder/ -name "file_prefix*" -mtime +30 -printf '%TD %TT %p\0' |
  sort -z |
  while IFS= read -r -d '' line
  do
    currentdate=${line%% *}
    if [ "$currentdate" = "$prevdate" ]
    then
      filepath=$(cut -d ' ' -f3- <<< $line)
      rm -- "$filepath"
    fi
    prevdate=$currentdate
  done

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

find выводит результаты с %TD %TT %p\0 вместо %TD %TT %p\n, что означает, что результаты разделены нулями, тогда sort -z использует этот разделенный нулями результат, и, наконец, while l oop является перезаписью * Сценарий 1053 *, но использует строки, разделенные нулями (что практически невозможно сделать с awk). В xargs rm нет вызова, потому что rm вызывается непосредственно внутри while l oop.

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

Та же дата и время

Если несколько «первый файл дня» происходят в одно и то же время в течение одного дня, пропускается только первый файл с «наименьшим» путем к файлу, т.е. отсортированный по алфавиту c символов. Если вы хотите сохранить все первые файлы дня в одно и то же время, это немного сложнее, но это выполнимо.

0 голосов
/ 02 марта 2020

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

d=2020-01-01
end_date=2020-02-03
while [ "$d" != $end_date ]; do
  d2=$(date -I -d "$d - 1 day")
  d=$(date -I -d "$d + 1 day")
  echo $d2
  echo $d
  find -type f -newerct "${d2}" ! -newerct "${d}" -printf "%T@ %Tc %p\n" | sort -n | tail -n +2 | awk '{print $9}' | xargs rm
done

Я бы предложил добавить пути и хэшировать бит rm xargs (только для печати и дважды проверьте, что вы удаляете).

Возможно, есть более элегантный способ сделать это, кроме материала для печати, но он работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...