J'essaie de garder un répertoire plein de fichiers journaux gérable. Tous les soirs, je veux supprimer tout sauf les 10 plus récents. Comment puis-je faire cela en une seule commande?
J'essaie de garder un répertoire plein de fichiers journaux gérable. Tous les soirs, je veux supprimer tout sauf les 10 plus récents. Comment puis-je faire cela en une seule commande?
Réponses:
Pour une solution portable et fiable, essayez ceci:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
La tail -n -10syntaxe de l'une des autres réponses ne semble pas fonctionner partout (c'est-à-dire pas sur mes systèmes RHEL5).
Et en utilisant $()ou ``sur la ligne de commande de rmcourt le risque de
xargscorrige ces deux problèmes car il déterminera automatiquement le nombre d'arguments pouvant être passés dans la limite de caractères et -d '\n'ne divisera le résultat qu'à la limite de la ligne de l'entrée. Techniquement, cela peut toujours causer des problèmes aux noms de fichiers contenant une nouvelle ligne, mais c'est beaucoup moins courant que les noms de fichiers comportant des espaces, et le seul moyen de contourner les nouvelles lignes serait beaucoup plus compliqué, impliquant probablement au moins awk, sinon perl.
Si vous n'avez pas xargs (peut-être d'anciens systèmes AIX?), Vous pouvez en faire une boucle:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
Cela sera un peu plus lent, car il génère un rmfichier distinct pour chaque fichier, tout en évitant les mises en garde 1 et 2 ci-dessus (mais souffre toujours de sauts de ligne dans les noms de fichiers).
head(1)page de manuel:-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
head, xargsindiquez des erreurs. Les options correctes sont head -n 10et xargs rm -f. La commande complète estls -1tr ./ | head -n 10 | xargs rm -rf
ls -1trle numéro UN n'est pas la lettre "L".
Le code que vous souhaitez inclure dans votre script est
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
L' -1option (numérique) imprime chaque fichier sur une seule ligne, pour plus de sécurité. L' -foption à lui rmdit d'ignorer les fichiers inexistants pour quand lsne renvoie rien.
/path/to/your/logsest juste fait que vous entriez le bon chemin. Pour trouver le bogue, exécutez les parties ls -t /path/...et ls -t /path/... | tail -n +11seul et vérifiez si le résultat est correct.
+au nombre avant. Cela tailne permet pas d’imprimer les n derniers éléments mais tous les éléments à partir du nième. Je me suis enregistré à nouveau et la commande ne devrait définitivement supprimer que les éléments plus anciens que les 10 fichiers les plus récents dans toutes les circonstances.
lsaffiche un nom de fichier, pas un chemin, alors vous rm -fallez essayer de supprimer les fichiers du répertoire actuel
Apparemment, analyser lsest mauvais .
Si chaque fichier est créé quotidiennement et que vous souhaitez conserver les fichiers créés au cours des 10 derniers jours, vous pouvez le faire:
find /path/to/files -mtime 10 -delete
Ou si chaque fichier est créé arbitrairement:
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 -deletesupprime uniquement les fichiers modifiés il y a exactement 10 jours. Les fichiers plus anciens ne seront pas supprimés. -mtime +11 -deletesupprime les fichiers modifiés il y a au moins 11 jours, laissant les 10 derniers jours des fichiers journaux.
%pau lieu de %Pest nécessaire sur le printfafin que les fichiers ont le chemin complet. Sinon le rm -rfne fonctionne pas.
J'ai modifié l'approche d'Isaac un peu.
Cela fonctionne maintenant avec le chemin souhaité:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
À partir d' ici :
#! /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
Dans Bash, vous pouvez essayer:
ls -1t | (i=0; while read f; do
if [ $i -lt 10 ]; then
((i++))
continue
else
rm -f "$f"
fi
done)
Cela saute les 10 derniers als supprime le reste. logrotate est peut-être mieux, je veux juste corriger les mauvaises réponses liées au shell.
Je ne suis pas sûr que cela puisse aider qui que ce soit, mais pour éviter d'éventuels problèmes avec les caractères débiles, je viens d'utiliser lsle tri pour ensuite utiliser les fichiers inodepour le supprimer.
Pour le répertoire en cours, les 10 fichiers les plus récents sont conservés en fonction de l’heure de modification.
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
J'avais besoin d'une solution élégante pour le busybox (routeur), toutes les solutions xargs ou array étaient inutiles pour moi - aucune commande de ce type n'y était disponible. trouver et mtime n'est pas la bonne réponse car nous parlons de 10 éléments et pas nécessairement de 10 jours. La réponse d'Espo était la plus courte et la plus propre et probablement la plus universelle.
Les erreurs d’espace et de suppression de fichiers sont toutes deux résolues simplement:
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Version un peu plus éducative: Nous pouvons tout faire si nous utilisons awk différemment. Normalement, j'utilise cette méthode pour transmettre (renvoyer) les variables de l'awk au sh. Comme nous lisons tout le temps que cela ne peut pas être fait, je vous prie de différer: voici la méthode.
Exemple pour les fichiers .tar sans problème concernant les espaces dans le nom du fichier. Pour tester, remplacez "rm" par "ls".
eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')
Explication:
ls -td *.tarrépertorie tous les fichiers .tar triés par heure. Pour appliquer à tous les fichiers du dossier actuel, supprimez la partie "d * .tar".
awk 'NR>7... saute les 7 premières lignes
print "rm \"" $0 "\"" construit une ligne: rm "nom de fichier"
eval l'exécute
Puisque nous utilisons rm, je n’utiliserais pas la commande ci-dessus dans un script! Une utilisation plus judicieuse est:
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
Dans le cas d'utilisation de ls -tcommande ne fera aucun mal sur des exemples aussi stupides que: touch 'foo " bar'et touch 'hello * world'. Non pas que nous créons jamais des fichiers avec de tels noms dans la vie réelle!
Sidenote. Si nous voulions transmettre une variable au sh de cette façon, nous modifierions simplement l'impression:
print "VarName="$1
pour définir la variable VarNamesur la valeur de $1. Plusieurs variables peuvent être créées en une fois. Cela VarNamedevient une variable sh normale et peut ensuite être utilisé dans un script ou un shell. Donc, pour créer des variables avec awk et les restituer au shell:
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"
Basé sur la réponse d'Isaac Freeman, mais travaillant sur n'importe quel répertoire:
ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --
Vous pouvez également définir un préfixe, comme $PATH_TO_DELETE/testFi*
Si vous utilisez *après la PATH lssortie des noms de fichiers absolus, au moins dans "mon" bash :)