Excluindo tudo, exceto os arquivos mais recentes


8

Digamos que eu tenho um diretório ḟoo/que contém muitos arquivos em algum tipo de estrutura de diretório. Eu preciso manter alguns deles, mas não todos.

Existe uma maneira de (no local) excluir todos eles, exceto (digamos) os 500 mais novos?

Respostas:


11

Faço essa tarefa regularmente e uso variantes do seguinte. É um pipeline que combina várias ferramentas simples: encontre todos os arquivos, acrescente o tempo de modificação do arquivo, classifique, remova o tempo de modificação do arquivo, exiba todas as linhas, exceto as 500 primeiras, e remova-as:

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

Alguns comentários:

  • Se você estiver usando o “bash”, você deve usar o “read -r file”, não apenas o “read file”.

  • Usar o "perl" para remover os arquivos é mais rápido (e também lida com caracteres "estranhos" nos nomes dos arquivos, melhor do que o loop while, a menos que você esteja usando o "read -r file"):

    ... | tail -n +501 | perl -wnle 'unlink() or warn "$_: unlink failed: $!\n"'
    
  • Algumas versões do "tail" não suportam a opção "-n", portanto você deve usar o "tail +501". Uma maneira portátil de pular as 500 primeiras linhas é

     ... | perl -wnle 'print if $. > 500' | ...
    
  • Não funcionará se os nomes dos seus arquivos contiverem novas linhas.

  • Não é necessário encontrar o GNU.

A combinação do acima exposto fornece:

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"'

Eu teria cuidado com isso rm -f.
um CVn

Funciona como um encanto! Isso deve estar disponível como um alias com os parâmetros $ path e $ count. Muito obrigado!
Dalibor Karlović

4

É assim que eu faria no Python 3., que também deve funcionar para outros sistemas operacionais. Depois de testar isso, descomente a linha que realmente remove os arquivos.

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)

4

Não conheço os "500 mais novos", mas, com o Find, você pode excluir itens com mais de X minutos / dias. Exemplo para arquivo e com mais de 2 dias:

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

Teste primeiro com:

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

Observe as barras invertidas e o espaço antes de "\;". Veja a página do manual find para mais informações.


O "(digamos) 500 mais novo" é a essência aqui, então não vejo como isso responde à pergunta original.
Peter John Acklam

Desculpe, não estava claro para mim.
AndreasM 17/11

3

se você poderia manter arquivos x dias / horas em vez do número x mais novo, poderia fazê-lo apenas com tmpwatch --ctime 7d


2

Eu acho que o -mtimee -neweropções de findcomando são úteis para você. Você pode ver man findpara mais informações.


0

por que não usar este código mais simples:

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

1
Como isso remove todos os arquivos, exceto os 500 arquivos mais recentes? E como isso lida com subdiretórios? Eu acho que você pode ter entendido mal a postagem original.
Peter John Acklam
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.