J'essaie de garder un répertoire plein de fichiers journaux gérable. Chaque nuit, je veux supprimer tous les fichiers sauf les 10 plus récents. Comment puis-je faire cela en une seule commande ?
Réponses
Trop de publicités?De aquí :
#! /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
Je ne suis pas sûr que cela puisse aider qui que ce soit, mais pour éviter les problèmes potentiels avec les caractères bancals, j'ai juste utilisé ls
pour effectuer le tri mais ensuite utiliser les fichiers inode
pour la suppression.
Pour le répertoire actuel, cela conserve les 10 fichiers les plus récents 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'est disponible ici. find 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, mais probablement la plus inversale.
Les erreurs avec des espaces et lorsqu'aucun fichier ne doit être supprimé sont toutes deux simplement résolues de la manière standard :
rm "$(ls -td *.tar | awk 'NR>7')" 2>&-
Version un peu plus éducative : On peut tout faire si on utilise l'awk différemment. Normalement, j'utilise cette méthode pour passer (retourner) des variables de l'awk vers le sh. Comme nous lisons tout le temps que ce n'est pas possible, je ne suis pas d'accord : 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 *.tar
liste tous les fichiers .tar triés par heure. Pour s'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 du fichier".
eval
l'exécute
Puisque nous utilisons rm
Je n'utiliserais pas la commande ci-dessus dans un script ! L'utilisation la plus sage est :
(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))
Dans le cas de l'utilisation de ls -t
ne fera pas de mal sur des exemples aussi stupides que ceux-là : touch 'foo " bar'
y touch 'hello * world'
. Non pas que nous créions des fichiers avec de tels noms dans la vie réelle !
Sidenote. Si nous voulions passer une variable au sh de cette manière, nous modifierions simplement le print :
print "VarName="$1
pour définir la variable VarName
à la valeur de $1
. Plusieurs variables peuvent être créées en une seule fois. Ce site VarName
devient une variable sh normale et peut être utilisée normalement dans un script ou script par la suite. Donc, pour créer des variables avec awk et les rendre à la script :
eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"