Ich versuche, ein Verzeichnis voller Protokolldateien übersichtlich zu halten. Nächtlich möchte ich alle bis auf die letzten 10 löschen. Wie kann ich das in einem einzigen Befehl tun?
Ich versuche, ein Verzeichnis voller Protokolldateien übersichtlich zu halten. Nächtlich möchte ich alle bis auf die letzten 10 löschen. Wie kann ich das in einem einzigen Befehl tun?
Antworten:
Versuchen Sie Folgendes, um eine tragbare und zuverlässige Lösung zu erhalten:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
Die tail -n -10Syntax in einer der anderen Antworten scheint nicht überall zu funktionieren (dh nicht auf meinen RHEL5-Systemen).
Und mit $()oder ``auf der Kommandozeile von rmläuft das Risiko von
xargsbehebt diese beiden Probleme, da automatisch ermittelt wird, wie viele Argumente innerhalb der Zeichenbegrenzung übergeben werden können, und mit dem -d '\n'wird nur an der Zeilengrenze der Eingabe geteilt. Technisch kann dies immer noch Probleme für Dateinamen mit einem Zeilenumbruch verursachen, aber das ist weitaus weniger verbreitet als bei Dateinamen mit Leerzeichen, und der einzige Weg, um die Zeilenumbrüche zu umgehen, wäre viel komplizierter, wahrscheinlich mit mindestens awk, wenn nicht mit Perl.
Wenn Sie keine xargs haben (alte AIX-Systeme vielleicht?), Könnten Sie eine Schleife daraus machen:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
Dies ist etwas langsamer, da rmfür jede Datei eine eigene Datei erstellt wird. Die obigen Einschränkungen 1 und 2 werden jedoch vermieden (es treten jedoch weiterhin Zeilenumbrüche in den Dateinamen auf).
head(1)Manpage:-n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file
headund xargsFehler geben. Richtige Optionen sind head -n 10und xargs rm -f. Voller Befehl istls -1tr ./ | head -n 10 | xargs rm -rf
ls -1tres sich bei der Nummer EINS nicht um den Buchstaben "L" handelt.
Der Code, den Sie in Ihr Skript aufnehmen möchten, lautet
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
Die -1(numerische) Option druckt aus Sicherheitsgründen jede Datei in einer einzelnen Zeile. Die -fOption, die rmangibt, dass nicht vorhandene Dateien ignoriert werden sollen, wenn lsnichts zurückgegeben wird.
/path/to/your/logsnur den richtigen Pfad eingeben. Um die Fehler der Teile ausführen ls -t /path/...und ls -t /path/... | tail -n +11allein und überprüfen , ob das Ergebnis korrekt ist.
+vor der Nummer. Es werden tailnicht die letzten n Elemente gedruckt, sondern alle Elemente, die ab dem n-ten beginnen. Ich habe erneut eingecheckt und der Befehl sollte auf jeden Fall nur Elemente entfernen, die älter als 10 der neuesten Dateien sind.
lsDrucke einen Dateinamen, keinen Pfad, also wirst rm -fdu versuchen, die Dateien im aktuellen Verzeichnis zu entfernen
Anscheinend ist Parsen lsböse .
Wenn jede Datei täglich erstellt wird und Sie Dateien behalten möchten, die innerhalb der letzten 10 Tage erstellt wurden, haben Sie folgende Möglichkeiten:
find /path/to/files -mtime 10 -delete
Oder wenn jede Datei willkürlich erstellt wird:
find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf
-mtime 10 -deletelöscht nur Dateien, die vor genau 10 Tagen geändert wurden. Ältere Dateien werden nicht gelöscht. -mtime +11 -deletelöscht Dateien, die vor 11 oder mehr Tagen geändert wurden, und belässt die letzten 10 Tage der Protokolldateien.
%panstelle von %Pwird auf dem benötigt, printfdamit die Dateien den vollen Pfad haben. Sonst klappt das rm -rfnicht.
Ich habe Isaacs Herangehensweise ein wenig modifiziert .
Es funktioniert jetzt mit einem gewünschten Pfad:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
Von hier :
#! /bin/sh
# keepnewest
#
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
#
# Usage: cleanup <dir> <number of files to keep>
#
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.
if [ $# -ne 2 ]; then
echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
exit 1
fi
cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
ls -t | tail -n $files_to_delete | xargs rm
if [ $? -ne 0 ]; then
echo "An error ocurred deleting the files"
exit 1
else
echo "$files_to_delete file(s) deleted."
fi
else
echo "nothing to delete!"
fi
In Bash können Sie versuchen:
ls -1t | (i=0; while read f; do
if [ $i -lt 10 ]; then
((i++))
continue
else
rm -f "$f"
fi
done)
Dies überspringt die 10 neuesten und löscht den Rest. logrotate kann besser sein, ich möchte nur die falschen Shell-bezogenen Antworten korrigieren.
Ich bin mir nicht sicher, ob dies jemandem helfen wird, aber um mögliche Probleme mit Wonky-Zeichen zu vermeiden, habe ich nur lsdie Sortierung durchgeführt, aber dann die Dateien inodezum Löschen verwendet.
Für das aktuelle Verzeichnis werden die letzten 10 Dateien basierend auf der Änderungszeit gespeichert.
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
Ich brauchte eine elegante Lösung für die Busybox (Router), alle xargs- oder Array-Lösungen waren für mich nutzlos - ein solcher Befehl war dort nicht verfügbar. find and mtime ist nicht die richtige Antwort, da es sich um 10 Artikel handelt und nicht unbedingt um 10 Tage. Espos Antwort war die kürzeste und sauberste und wahrscheinlich die unversalste.
Fehler mit Leerzeichen und wenn keine Dateien gelöscht werden sollen, werden beide einfach auf die übliche Weise behoben:
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Etwas lehrreichere Version: Wir können alles machen, wenn wir awk anders benutzen. Normalerweise benutze ich diese Methode, um Variablen von awk an sh zu übergeben (zurückzugeben). Da wir die ganze Zeit lesen, was nicht möglich ist, möchte ich unterscheiden: Hier ist die Methode.
Beispiel für .tar-Dateien ohne Probleme bezüglich der Leerzeichen im Dateinamen. Ersetzen Sie zum Testen "rm" durch "ls".
eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')
Erläuterung:
ls -td *.tarlistet alle .tar-Dateien nach der Zeit sortiert auf. Entfernen Sie den Teil "d * .tar", um ihn auf alle Dateien im aktuellen Ordner anzuwenden
awk 'NR>7... überspringt die ersten 7 Zeilen
print "rm \"" $0 "\"" erstellt eine Zeile: rm "Dateiname"
eval führt es aus
Da wir verwenden rm, würde ich den obigen Befehl nicht in einem Skript verwenden! Klügerer Gebrauch ist:
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
Im Falle der Verwendung von ls -tbefehlen werden solche albernen Beispiele wie: touch 'foo " bar'und keinen Schaden anrichten touch 'hello * world'. Nicht, dass wir jemals Dateien mit solchen Namen im wirklichen Leben erstellen würden!
Randnotiz. Wenn wir auf diese Weise eine Variable an sh übergeben möchten, ändern wir einfach den Ausdruck:
print "VarName="$1
um die Variable VarNameauf den Wert von zu setzen $1. Es können mehrere Variablen auf einmal erstellt werden. Dies VarNamewird eine normale sh-Variable und kann danach normalerweise in einem Skript oder einer Shell verwendet werden. So erstellen Sie Variablen mit awk und geben sie an die Shell zurück:
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"
Basierend auf der Antwort von Isaac Freeman, aber in jedem Verzeichnis:
ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --
Sie können auch ein Präfix festlegen, z $PATH_TO_DELETE/testFi*
Wenn Sie *nach dem verwenden, PATH lswerden absolute Dateinamen ausgegeben, zumindest in "my" bash :)