Ich möchte ein Skript in cronjob einfügen, das zu einer bestimmten Zeit ausgeführt wird. Wenn die Anzahl der Dateien mehr als 60 beträgt, werden die ältesten Dateien aus diesem Ordner gelöscht. Zuletzt rein, zuerst raus. Ich habe versucht,
#!/bin/ksh
for dir in /home/DABA_BACKUP
do
cd $dir
count_files=`ls -lrt | wc -l`
if [ $count_files -gt 60 ];
then
todelete=$(($count_files-60))
for part in `ls -1rt`
do
if [ $todelete -gt 0 ]
then
rm -rf $part
todelete=$(($todelete-1))
fi
done
fi
done
Dies sind alles Sicherungsdateien, die täglich gespeichert und benannt werden backup_$date
. Ist das ok?
shell-script
ksh
file-management
pmaipmui
quelle
quelle
ls
Optionen-lrt
und um eine Liste in der for-Schleife zu erstellen, benötigen Sie keinels
Option-1
. Freie Variablenerweiterungen ("$dir"
und"$part"
) sollten in Anführungszeichen gesetzt werden. Anstelle der Backtics verwenden$(ls | wc -l)
.backup_$date
aber was ist$date
? Ist es114-06-2015
? OderSun Jun 14 15:06:53 EEST 2015
? Wenn Sie uns genau sagen, was es ist, können wir Ihnen dies robuster und effizienter machen.Antworten:
Nein, zum einen wird es bei Dateinamen mit Zeilenumbrüchen kaputt gehen. Es ist auch komplexer als nötig und birgt alle Gefahren beim Parsen von ls .
Eine bessere Version wäre (mit GNU-Tools):
Beachten Sie, dass dies voraussetzt, dass sich alle Dateien im selben Dateisystem befinden und unerwartete Ergebnisse liefern können (z. B. das Löschen falscher Dateien), wenn dies nicht der Fall ist. Es funktioniert auch nicht gut, wenn mehrere Hardlinks auf denselben Inode verweisen.
quelle
ls
.-l
. Ich habe auch keine Ahnung, warum Sie Solaris erwähnen. Ich bin mit Ihrer Meinung zu diesem Beitrag genauso vertraut wie mit meiner. Lassen Sie es uns nicht noch einmal aufwärmen. Ich bin,find
weil das der beste Weg ist, Dateien durch Inodes zu löschen. Ich würde mich freuen, von einem besseren zu hören (und das wäre ein wirklich konstruktiver Kommentar). Und ja, dies ist keine gute Antwort und ich würde es lieber nicht akzeptieren (und ich habe dies geschrieben, bevor ich Ihren letzten Kommentar gesehen habe). Da es jedoch akzeptiert wird, habe ich zumindest versucht, es i) funktionieren zu lassen, im Gegensatz zur vorherigen Version und ii) robust.Für die zsh-Unwissenden ;-):
for var (list) cmd
: kurze Version derfor var in list; do cmd; done
Schleife (erinnert an dieperl
Syntax).$dir
:zsh
Variablen haben zitiert , wie sie in anderen Shells nicht brauchen , wiezsh
hat explizitesplit
undglob
Betreiber macht so nicht implizite Split + glob auf Parameter Expansion.*(...)
: glob mit glob qualifiers :N
:nullglob
: Die glob zu nichts expandiert statt einen Fehler zu erhöhen , wenn es nicht übereinstimmt.m
: O rder die generierten Dateien auf m NDERUNG Zeit (jüngste zuerst).[61,-1]
: Wählen Sie aus dieser geordneten Liste die 61. bis letzte aus.Entfernt also im Grunde alle bis auf die 60 jüngsten Dateien.
quelle
NOm
tut?om
, zuerst mit dem Jüngsten zu sortieren (wie inls -t
).So erhalten Sie eine Liste der ältesten zu löschenden Einträge (wobei die 60 neuesten Einträge beibehalten werden):
Beachten Sie, dass das Hauptproblem Ihres Ansatzes auch hier noch angegangen werden muss: Wie gehe ich mit Dateien mit Zeilenumbrüchen um, falls es darauf ankommt? Andernfalls können Sie einfach Folgendes verwenden (um Ihr recht komplexes Programm zu ersetzen):
Hinweis: Da Sie anscheinend tägliche Backups haben, können Sie möglicherweise auch einen Ansatz verwenden, der auf den Dateidaten und basiert
find
. wie in:(wo der
ls
Befehl - nach sorgfältiger Prüfung der korrekten Funktion! - durch den entsprechendenrm
Befehl ersetzt würde).quelle
xargs
auch davon ausgegangen wird, dass der Dateiname kein Leerzeichen, Tabulatoren, Zeilenumbrüche (andere Formen von Leerzeichen je nach Gebietsschema und Xargs-Implementierung), einfache Anführungszeichen, doppelte Anführungszeichen und Backslash enthält. Möglicherweise möchten Sie der rm-Cmdline ein - hinzufügen, um Probleme mit Dateien zu vermeiden, deren Name mit - beginnt. (wahrscheinlich kein Problem für das OP, aber es lohnt sich, es hier für alle zu erwähnen, die mit einem ähnlichen Bedarf hierher kommen).Dies wird für Sie funktionieren. Es werden die ältesten Dateien im aktuellen Verzeichnis bis zu einer Zählung von 60. löschen Sie dies tun , werden durch das Parsen
ls
robust , und es wird es tun , ohne irgendwelche Annahmen über Ihre Dateinamen zu machen - sie könnten etwas genannt werden und müssen nicht durch Daten genannt werden. Dies funktioniert nur für eine Auflistung des aktuellen Verzeichnisses und für den Fall, dass Sie ein POSIXls
installiert haben (und nicht durch eine böse Shell-Funktion maskiertalias
sind , aber es wird abgedeckt) .Die obige Lösung wendet nur einige sehr grundlegende Shell-Aufteilungen auf einige sehr grundlegende Unix-Pfadnamen an. Es stellt sicher, dass
ls
alle Nicht-Punkt-Dateien im aktuellen Verzeichnis eine pro Zeile wie folgt aufgelistet werden:Nun, jeder von ihnen könnte auch neue Zeilen dazwischen haben, aber das wäre kein Problem. Denn in diesem Fall würden sie wie folgt aufgelistet:
...und so weiter. Und die Zeilenumbrüche stören uns sowieso nicht - weil wir uns nicht auf sie aufteilen. Warum sollten wir? Wir arbeiten mit Pfadnamen, wir sollten uns auf den Pfadbegrenzer aufteilen, und so machen wir das :
IFS=/
.Das klappt ein bisschen komisch. Am Ende haben wir eine Argumentliste, die so aussieht:
... aber das ist eigentlich sehr gut für uns, weil wir unsere Argumente, die von der Shell als Dateien behandelt werden (oder, falls wir dies vermeiden möchten, Symlinks) , so lange verzögern können , bis wir dazu bereit
rm
sind.Sobald wir unsere Dateiliste haben, müssen wir nur noch
shift
unser erstes Argument entfernen. Überprüfen Sie, ob wir derzeit mehr als 60 Argumente haben, und lehnen Sie es wahrscheinlich inrm
ein untergeordnetes Verzeichnis ab (obwohl das natürlich ganz bei Ihnen liegt). und ansonstenrm
unser erstes Argument abzüglich der letzten beiden Zeichen. Wir haben keine Sorgen zu machen über die letzte letzte Argument - die aus der Anlage ersichtliche Zeit nicht hat - weil wir nie dorthin zu gelangen, und stattdessen bei 60 beenden Wenn wir es bis hierher für eine Iteration gemacht haben , dann haben wir einfach versuchen Sie es erneut und durchlaufen Sie die Arg-Liste auf diese Weise, bis wir sie zu unserer Zufriedenheit beschnitten haben.Wie bricht das? Meines Wissens nicht, aber ich habe es zugelassen - wenn zu irgendeinem Zeitpunkt ein unerwarteter Fehler auftritt, bricht die Schleife und die Funktion gibt eine andere als 0 zurück.
Und so
ls
können Sie Ihre Auflistung im aktuellen Verzeichnis ohne Probleme für Sie erledigen. Sie können es zulassen, dass Ihre Argumente für Sie sortiert werden, solange Sie sie zuverlässig abgrenzen können. Aus diesem Grund funktioniert dies nur für das aktuelle Verzeichnis wie geschrieben - mehr als ein Trennzeichen in einer Pfadzeichenfolge würde eine andere Begrenzungsstufe erfordern, die durch doppeltes Ausklammern für alle außer dem letzten in NUL-Felder erfolgen könnte , aber das ist mir jetzt egal.quelle
Wenn Sie wissen, dass alle Dateien den Namen backup_ * haben, sollten Sie dies in den Befehl ls aufnehmen, damit Sie nur diese und keine Dateien verarbeiten, die versehentlich im Verzeichnis landen. Dann wird ls in einer Pipe verwendet, es wird nur 1 Datei pro Zeile aufgelistet und dann nur gezählt, ohne dass eine Sortierung erforderlich ist
und
quelle
ls
Ausgabe in Skripten zu vermeiden . Sie könntenfind
stattdessen verwenden.find
bietet hier, was vorzuziehen istls
? Einmal schrieb jemand einen ziemlich fehlerbehafteten Blog-Beitrag über das Parsenls
und aus irgendeinem Grund behandelt ihn die gesamte Linux-Community wie den Pentateuch. Schauen Sie, die wenigen gültigen Punkte, die im Blog-Beitrag gemacht wurden, gelten auch fürfind
diesen Fall.