Excluindo tudo, exceto os arquivos mais recentes

8

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

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

    
por Dalibor Karlović 17.11.2011 / 08:45

6 respostas

11

Eu faço essa tarefa regularmente e uso variantes do seguinte. É um pipeline que combina várias ferramentas simples: Encontre todos os arquivos, prefixar o horário de modificação do arquivo, classificar, remover o tempo de modificação do arquivo, exibir todas as linhas, exceto as 500 primeiras, e removê-las:

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ê está usando “bash”, você deve usar “read -r file”, não apenas “read file”.

  • Usar “perl” para remover os arquivos é mais rápido (e também lida com caracteres “estranhos” nos nomes de arquivos melhor que o loop while, a menos que você esteja usando “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”, então você deve usar “tail +501”. Uma maneira portátil de pular as 500 primeiras linhas é

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

  • Não requer o GNU find.

Combinar o que foi mencionado acima 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"'
    
por 17.11.2011 / 09:34
4

É assim que eu faria no Python 3. que também deve funcionar para outros sistemas operacionais. Depois de testar isso, certifique-se de descomentar 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)
    
por 17.11.2011 / 09:53
4

Eu não sei sobre o "500 mais novo", mas com o recurso "Localizar", você pode excluir itens com mais de X minutos / dias. Exemplo para arquivo e 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 \{\} \;

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

    
por 17.11.2011 / 08:57
3

se você pudesse manter os arquivos x dias / horas de idade em vez do número x mais recente, você poderia fazer isso apenas com tmpwatch --ctime 7d

    
por 17.11.2011 / 10:58
2

Acho que as opções -mtime e -newer do comando find são úteis para você. Você pode ver man find para mais informações.

    
por 17.11.2011 / 08:58
0

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

$ ls -t1 foo/| xargs -d '\n' rm --
    
por 17.11.2011 / 13:25