Nehmen wir an, ich habe ein Verzeichnis, ḟoo/
das viele Dateien in einer Art Verzeichnisstruktur enthält. Ich muss einige von ihnen behalten, aber nicht alle.
Gibt es eine Möglichkeit, alle zu löschen, außer (sagen wir) 500 neuesten?
Nehmen wir an, ich habe ein Verzeichnis, ḟoo/
das viele Dateien in einer Art Verzeichnisstruktur enthält. Ich muss einige von ihnen behalten, aber nicht alle.
Gibt es eine Möglichkeit, alle zu löschen, außer (sagen wir) 500 neuesten?
Antworten:
Ich mache diese Aufgabe regelmäßig und verwende Varianten der folgenden. Es handelt sich um eine Pipeline, die verschiedene einfache Tools kombiniert: Suchen Sie alle Dateien, stellen Sie die Änderungszeit für Dateien voran, sortieren Sie, entfernen Sie die Änderungszeit für Dateien, zeigen Sie alle Zeilen mit Ausnahme der 500 zuerst an und entfernen Sie sie:
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
Ein paar Kommentare:
Wenn Sie "bash" verwenden, sollten Sie "read -r file" verwenden, nicht nur "read file".
Die Verwendung von "Perl" zum Entfernen der Dateien ist schneller (und behandelt auch "seltsame" Zeichen in den Dateinamen besser als die while-Schleife, es sei denn, Sie verwenden "read -r file"):
... | tail -n +501 | perl -wnle 'unlink() or warn "$_: unlink failed: $!\n"'
Einige Versionen von "tail" unterstützen die Option "-n" nicht, daher müssen Sie "tail +501" verwenden. Eine tragbare Möglichkeit, die 500 ersten Zeilen zu überspringen, ist
... | perl -wnle 'print if $. > 500' | ...
Es funktioniert nicht, wenn Ihre Dateinamen Zeilenumbrüche enthalten.
Es ist keine GNU-Suche erforderlich.
Wenn Sie das oben Genannte kombinieren, erhalten Sie:
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"'
So würde ich es in Python 3 machen, das auch für andere Betriebssysteme funktionieren sollte. Stellen Sie nach dem Testen sicher, dass Sie die Zeile auskommentieren, in der die Dateien tatsächlich entfernt werden.
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)
Ich weiß nichts über die "500 neuesten", aber mit find können Sie Dinge löschen, die älter als X Minuten / Tage sind. Beispiel für Datei und älter als 2 Tage:
find foo/ -mtime +2 -a -type f -exec rm -fv \{\} \;
Testen Sie zuerst mit:
find foo/ -mtime +2 -a -type f -exec ls -al \{\} \;
Beachten Sie die Backslashes und das Leerzeichen vor "\;". Weitere Informationen finden Sie auf der Manpage zum Suchen.
Warum nicht diesen einfacheren Code verwenden:
$ ls -t1 foo/| xargs -d '\n' rm --
rm -f
.