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?
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:
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"'
É 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)
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.
por que não usar este código mais simples:
$ ls -t1 foo/| xargs -d '\n' rm --
rm -f
.