it-swarm.com.de

Wie lösche ich alle 10 neuesten Dateien in Linux?

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?

44
user75814

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 -10-Syntax in einer der anderen Antworten scheint nicht überall zu funktionieren (d. H. Nicht auf meinen RHEL5-Systemen).

Und die Verwendung von $() oder `` in der Befehlszeile von rm birgt das Risiko von

  1. teilen von Dateinamen mit Leerzeichen und
  2. überschreitung der maximalen Anzahl von Kommandozeilenzeichen.

xargs behebt beide 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 Perl.

Wenn Sie keine xargs haben (alte AIX-Systeme vielleicht?), Können 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 für jede Datei eine eigene rm erzeugt wird. Die obigen Einschränkungen 1 und 2 werden jedoch vermieden (es treten jedoch weiterhin Zeilenumbrüche in den Dateinamen auf).

55
Isaac Freeman

Der Code, den Sie in Ihr Skript aufnehmen möchten, lautet

 rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)

Mit der Option -1 (numerisch eins) wird jede Datei aus Sicherheitsgründen in einer einzelnen Zeile gedruckt. Die Option -f für rm weist an, nicht vorhandene Dateien zu ignorieren, wenn ls nichts zurückgibt.

20
Daniel Böhmer

Anscheinend ist Parsen ls bö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
11
TheOne

Ein Tool wie Logrotate erledigt dies für Sie. Dies erleichtert die Protokollverwaltung erheblich. Sie können auch zusätzliche Bereinigungsroutinen einschließen, die als Halo vorgeschlagen werden.

9
BillThor

Ich habe Isaacs Ansatz 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
2
Sebastian U.

ich bin mir nicht sicher, ob dies jemandem helfen wird, aber um mögliche Probleme mit Wonky-Zeichen zu vermeiden, habe ich gerade ls verwendet, um die Sortierung durchzuführen, aber dann die Dateien inode zum 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 {} \;

1
Flo Woo

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 ist vielleicht besser, ich möchte nur die falschen Shell-bezogenen Antworten korrigieren.

1
Hauke Laging

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
1
manoflinux

Ich stimme zu, dass das Parsen von ls böse ist!

Stellen Sie sicher, dass sich nur die letzten 5 Dateien im Pfad /srv/backups befinden.

find /srv/backups -maxdepth 1 -type f -printf '%Ts\t%P\n' \
    | sort -rn \
    | tail -n +6 \
    | cut -f2- \
    | xargs -r r
0
h0tw1r3

Ich brauchte eine elegante Lösung für die Busybox (Router), alle xargs- oder Array-Lösungen waren für mich nutzlos - dort gibt es keinen solchen Befehl. 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 *.tar listet alle .tar-Dateien nach der Uhrzeit 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 rm verwenden, 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 -t wird der Befehl solchen albernen Beispielen wie: touch 'foo " bar' und touch 'hello * world' keinen Schaden zufügen. 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 VarName auf den Wert von $1 zu setzen. Es können mehrere Variablen auf einmal erstellt werden. Diese VarName wird zu einer normalen sh-Variablen 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"
0
Pila