Tout supprimer sauf les fichiers les plus récents

8

Disons que j'ai un répertoire ḟoo/qui contient beaucoup de fichiers dans une sorte de structure de répertoires. Je dois en garder certains, mais pas tout.

Existe-t-il un moyen (en place) de les supprimer tous sauf (disons) les 500 plus récents?

Dalibor Karlović
la source

Réponses:

11

Je fais cette tâche régulièrement et j'utilise des variantes des éléments suivants. Il s'agit d'un pipeline combinant divers outils simples: recherchez tous les fichiers, ajoutez l'heure de modification des fichiers, triez, supprimez l'heure de modification des fichiers, affichez toutes les lignes sauf les 500 premières et supprimez-les:

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

Quelques commentaires:

  • Si vous utilisez "bash", vous devez utiliser "read -r file", pas seulement "read file".

  • L'utilisation de "perl" pour supprimer les fichiers est plus rapide (et gère également les caractères "bizarres" dans les noms de fichiers mieux que la boucle while, sauf si vous utilisez "read -r file"):

    ... | tail -n +501 | perl -wnle 'unlink() or warn "$_: unlink failed: $!\n"'
    
  • Certaines versions de «tail» ne prennent pas en charge l'option «-n», vous devez donc utiliser «tail +501». Une façon portable de sauter les 500 premières lignes est

     ... | perl -wnle 'print if $. > 500' | ...
    
  • Cela ne fonctionnera pas si vos noms de fichiers contiennent des retours à la ligne.

  • Il ne nécessite pas de recherche GNU.

La combinaison de ce qui précède vous donne:

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"'
Peter John Acklam
la source
Je serais prudent rm -fcependant.
un CVn
Fonctionne comme un charme! Il doit être disponible sous forme d'alias avec les paramètres $ path et $ count. Merci beaucoup!
Dalibor Karlović
4

C'est ainsi que je le ferais en Python 3. qui devrait également fonctionner pour d'autres systèmes d'exploitation. Après avoir testé cela, assurez-vous de décommenter la ligne qui supprime réellement les fichiers.

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)
jftuga
la source
4

Je ne connais pas les "500 plus récents", mais avec find, vous pouvez supprimer des éléments vieux de X minutes / jours. Exemple pour fichier et plus de 2 jours:

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

Testez d'abord avec:

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

Faites attention aux barres obliques inverses et à l'espace avant "\;". Consultez la page de manuel find pour plus d'informations.

AndreasM
la source
Le «(disons) 500 plus récent» est l'essence ici, donc je ne vois pas comment cela répond à la question d'origine.
Peter John Acklam
Désolé, ce n'était pas clair pour moi.
AndreasM
3

si vous pouviez conserver les fichiers vieux de x jours / heures au lieu du plus récent numéro x, vous pouvez le faire simplement avec tmpwatch --ctime 7d

Sirex
la source
2

Je pense que le -mtimeet les -neweroptions de findcommande sont utiles pour vous. Vous pouvez voir man findpour plus d'informations.

Khaled
la source
0

pourquoi ne pas utiliser ce code plus simple:

$ ls -t1 foo/| xargs -d '\n' rm --
eppesuig
la source
1
Comment cela supprime-t-il tous les fichiers à l'exception des 500 fichiers les plus récents? Et comment cela gère-t-il les sous-répertoires? Je pense que vous avez peut-être mal compris la publication d'origine.
Peter John Acklam