Назад | Перейти на главную страницу

Удаление всего, кроме самых новых файлов

Допустим, у меня есть каталог ḟoo/ который содержит множество файлов в какой-то структуре каталогов. Мне нужно оставить некоторые из них, но не все.

Есть ли способ (на месте) удалить все из них, кроме (скажем) 500 самых новых?

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

find foo/ -type f | perl -wple 'printf "%12u ", (stat)[9]' | \
    sort -r | cut -c14- | tail -n +501 | \
    while read file; do rm -f -- "$file"; done

Несколько комментариев:

  • Если вы используете «bash», вам следует использовать «чтение -r файл», а не просто «чтение файла».

  • Использование «perl» для удаления файлов происходит быстрее (а также обрабатывает «странные» символы в именах файлов лучше, чем цикл while, если вы не используете «read -r file»):

    ... | tail -n +501 | perl -wnle 'unlink() or warn "$_: unlink failed: $!\n"'
    
  • Некоторые версии «tail» не поддерживают параметр «-n», поэтому вы должны использовать «tail +501». Портативный способ пропустить 500 первых строк -

     ... | perl -wnle 'print if $. > 500' | ...
    
  • Это не сработает, если имена ваших файлов содержат символы новой строки.

  • Это не требует поиска GNU.

Объединение вышеперечисленного дает вам:

find foo/ -type f | perl -wple 'printf "%12u ", (stat)[9]' | \
    sort -r | cut -c14- | perl -wnle 'print if $. > 500' | \
    perl -wnle 'unlink() or warn "$_: unlink failed: $!\n"'

Так я бы сделал это в Python 3., который также должен работать для других ОС. После тестирования не забудьте раскомментировать строку, которая фактически удаляет файлы.

import os,os.path
from collections import defaultdict

FILES_TO_KEEP = 500
ROOT_PATH = r'/tmp/'

tree = defaultdict(list)

# create a dictionary containing file names with their date as the key
for root, dirs, files in os.walk(ROOT_PATH):
    for name in files:
        fname = os.path.join(root,name)
        fdate = os.path.getmtime( fname )
        tree[fdate].append(fname)

# sort this dictionary by date
# locate where the newer files (that you want to keep) end
count = 0
inorder = sorted(tree.keys(),reverse=True)
for key in inorder:
    count += len(tree[key])
    if count >= FILES_TO_KEEP:
        last_key = key
        break

# now you know where the newer files end, older files begin within the dict
# act accordingly
for key in inorder:
    if key < last_key:
        for f in tree[key]:
            print("remove ", f)
            # uncomment this next line to actually remove files
            #os.remove(f)
    else:
        for f in tree[key]:
            print("keep    ", f)

Я не знаю, что такое «500 новейших», но с помощью find вы можете удалить вещи старше X минут / дней. Пример для файла старше 2 дней:

find foo/ -mtime +2 -a -type f -exec rm -fv \{\} \;

Сначала проверьте:

find foo/ -mtime +2 -a -type f -exec ls -al \{\} \;

Обратите внимание на обратную косую черту и пробел перед "\;". См. Справочную страницу find для получения дополнительной информации.

если бы вы могли хранить файлы старше x дней / часов вместо самого нового числа x, вы могли бы сделать это просто с tmpwatch --ctime 7d

я думаю -mtime и -newer варианты find вам пригодятся. Ты можешь видеть man find для получения дополнительной информации.

почему бы не использовать этот более простой код:

$ ls -t1 foo/| xargs -d '\n' rm --