Compter et supprimer les anciens fichiers à l’aide d’Unix find

Je veux supprimer des fichiers dans $DIR_TO_CLEAN plus anciens que $DAYS_TO_SAVE jours. Facile:

 find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec rm {} \; 

Je suppose que nous pourrions append un indicateur de -type f ou un indicateur -f pour rm , mais je voudrais vraiment compter le nombre de fichiers supprimés.

Nous pourrions le faire naïvement:

 DELETE_COUNT=`find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE | wc -l` find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec rm {} \; 

Mais cette solution laisse beaucoup à désirer. Outre la duplication de commandes, cet extrait surestime le compte si rm n’a pas pu supprimer un fichier.

Je suis tout à fait à l’aise avec la redirection, les tuyaux (y compris ceux nommés), les sous- xargs , xargs , tee , etc., mais j’ai hâte d’apprendre de nouveaux trucs. Je voudrais une solution qui fonctionne à la fois sur bash et ksh.

Comment comptez-vous le nombre de fichiers supprimés par find ?

Vous pouvez simplement utiliser bash dans find:

 find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec bash -c 'printf "Total: %d\n" $#; rm "$@"' _ {} + 

Bien sûr, cela peut appeler bash -c … plus d’une fois si le nombre de fichiers trouvés est plus grand que MAX_ARGS, et cela peut aussi surestimer le compte en cas d’échec de rm. Mais résoudre ces problèmes devient désordonné:

 find "$DIR_TO_CLEAN" -mtime +$DAYS_TO_SAVE -exec bash -c 'printf "count=0; for f; do rm "$f" && (( count++ )); done; printf "Total: %d\n" $count' _ {} + 

Cette solution pour éviter les limites MAX_ARGS évite toute recherche. Si vous en avez besoin, vous devrez utiliser la globalisation récursive, disponible uniquement dans les nouveaux shells. ( globstar est une fonctionnalité de bash 4.)

 shopt -s globstar # Assume DAYS_TO_SAVE reformatted to how touch -m expects it. (Exercise for the reader.) touch -m "$DAYS_TO_SAVE" referencefile count=0 for file in "$DIR_TO_CLEAN/"**/*; do if [[ referencefile -nt "$file" ]]; then rm "$file" && (( count++ )) fi done printf 'Total: %d\n' "$count" 

Voici une approche utilisant find avec printf (la recherche ssortingctement conforme n’a pas printf, mais vous pouvez utiliser printf comme un utilitaire autonome dans ce cas).

 find "$DIR_TO_CLEAN" -type -f -mtime "+$DAYS_TO_SAVE" -exec rm {} \; -printf '.' | wc -c find "$DIR_TO_CLEAN" -type -f -mtime "+$DAYS_TO_SAVE" -exec rm {} \; -exec printf '.' \; | wc -c 

-exec et -exec pour une solution canalisée:

 find "$DIR_TO_CLEAN" -type f -mtime +$DAYS_TO_SAVE -print0 \ | awk -v RS='\0' -v ORS='\0' '{ print } END { print NR }' \ | xargs -0 rm 

Utiliser awk pour compter les correspondances et les transmettre à rm .

Mettre à jour:

kojiro m’a fait comprendre que la solution ci-dessus ne compte pas le taux de réussite / échec de rm . Comme awk a des problèmes avec les fichiers mal nommés, je pense que la solution suivante pourrait être meilleure:

 find "${DIR_TO_CLEAN?}" -type f -mtime +${DAYS_TO_SAVE?} -print0 | ( success=0 fail=0 while read -rd $'\0' file; do if rm "$file" 2> /dev/null; then (( success++ )) else (( fail++ )) fi done echo $success $fail )