J'essaie de modifier script de Sergiy pour qu'il agisse de manière récursive (actuellement, il ne supprime qu'un fichier, mais je voudrais qu'il supprime tous les fichiers jusqu'à ce que la limite de fichier maximale soit atteinte). Mais je n'arrive pas à comprendre. Je pense que je devrais pouvoir modifier la première fonction ("delete old") pour lire plusieurs horodatages et la transmettre à la ligne suivante, mais je ne suis pas familier avec cette commande et je ne trouve aucune information à ce sujet. Toute idée serait appréciée!
Si vous souhaitez que le script continue à fonctionner sur un répertoire, sans passer par les sous-répertoires, le comptage et la suppression peuvent être effectués dans une boucle while
. La dernière section de la fonction main
devrait être modifiée pour ressembler à ceci:
local file_inodes=$(get_files)
while filecount_above_limit
do
printf "@@@ File count in %s is above %d." "$directory" $max_files
printf "Will delete oldest\n"
sort -k1 -n <<< "$file_inodes" | delete_oldest
local file_inodes=$(get_files)
done
printf "@@@ File count in %s is below %d." "$directory" $max_files
printf "Exiting normally"
Attention!
Le problème de cette modification simple est que, si vous n’avez pas fait de commentaire dans la ligne de suppression située en haut, le script se mettra en boucle sans fin, car il recalculera le nombre de fichiers après chaque suppression. Si un fichier n'est pas supprimé, le nombre de fichiers reste le même et la boucle ne se ferme jamais.
Il est possible de modifier le script de manière plus complexe, de supprimer l'inode du fichier du tableau file_inodes
une fois supprimé et d'incrémenter négativement la variable file_count
plutôt que de répéter la ligne local file_inodes=$(get_files)
. Cela réglerait le problème de non-suppression, mais je le laisserai à quelqu'un d'autre.
Je suggérerais une autre solution, qui ira de manière récursive dans l’arborescence des répertoires de destination et supprimera tous les fichiers, à l’exception d’un certain nombre prédéfini de nouveaux fichiers. Cette solution est basée sur: (1) script bash récursif et (2) explication d'un script shell pour imprimer récursivement une arborescence de répertoires complète .
1. Créez un fichier script exécutable, appelé walkr
(, marchez et supprimez ), qui se trouve dans _/usr/local/bin
_ pour être accessible en tant que commande Shell ( étapes plus détaillées ).
2. Le contenu du script walkr
est assez simple:
_#!/bin/bash
[[ -z "${NFK}" ]] && NFK='7' || NFK="$NFK"
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}"
file_operations() {
local IFS=$'\t\n' # Change the value of the Internal Field Separator locally
rm $(ls -lt | grep -Po '^-.*[0-9]{2}:[0-9]{2} \K.*' | tail -n +"$((NFK+1))") 2>/dev/null
}
walk() {
cd "$1" && file_operations # Change directory to the destination path and call the above function
for item in "$1"/*; do [[ -d "$item" ]] && walk "$item"; done # Make the recursion
}
walk "${ABS_PATH}"
_
3. Explication:
Au début, le script vérifiera si la variable _$NFK
_ (qui détermine le nombre de fichiers à conserver) est définie à l’avance - la condition _[[ -z "${NFK}" ]]
_. S'il n'est pas défini, la valeur par défaut est _7
_.
Ensuite, le script traite du chemin de destination (stdin de la commande). S'il n'est pas fourni - la condition _[[ -z "${1}" ]]
_ - le script fonctionnera dans le répertoire en cours.
Enfin, la fonction principale walk()
sera exécutée.
La fonction walk()
:
Initialement, le répertoire sera remplacé par le chemin de destination _cd "$1"
_, puis il appellera la fonction file_operations()
, qui fonctionnera à l'intérieur.
En outre, pour chaque _$item
_, dans le répertoire en cours _"$1"/*
_, qui est également le répertoire _[[ -d "$item" ]]
_, la fonction walk()
sera exécutée à nouveau, ainsi nous créons la récursion .
La fonction file_operations()
:
Initialement, il va définir une valeur locale de variable Bash interne _$IFS
_, donc nous pouvons gérer correctement _<the list of the files to be removed>
_, peu importe qu'il y ait des espaces à l'intérieur du noms de fichiers séparés.
De plus, la commande rm $(<the list of the files to be removed>)
sera exécutée. La redirection des erreurs _2>/dev/null
_ est pour ces cas où il n'y a rien à supprimer. _<the list of the files to be removed>
_ est pris de cette façon:
La commande _ls -lt
_ répertorie le contenu du répertoire en cours au format de liste longue _-l
_ et la liste est triée par heure de modification, la plus récente en premier _-t
_. Et cette liste est transmise _|
_ à la commande suivante.
La commande suivante _grep -Po '^-.*[0-9]{2}:[0-9]{2} \K.*'
_ rognera ces lignes commençant par _^
_ par _-
_†, depuis leur début jusqu’au motif _[0-9]{2}:[0-9]{2}_
_‡. L'option _-P
_ avec l'option _-o
_ générera les chaînes correspondant au modèle _^-.*[0-9]{2}:[0-9]{2}_
_. La notification _\K
_ ignorera la partie correspondante avant elle-même. ( source - cette réponse utile )
†Ainsi, nous n'obtiendrons que les noms des fichiers de la liste. Dans la sortie de _ls -l
_, les lignes décrivant les répertoires commencent par d
, et celles des fichiers commencent par _-
_. ( source de l'idée )
‡Ce modèle correspond au format d'heure _00:00
_.
Enfin, la commande tail -n +"$((NFK+1))
coupera les premières lignes de notre liste de fichiers. Le nombre de ces premières lignes est égal à la valeur de _$NFK
_ plus 1, il s'agit d'une exigence de la commande tail
.
4. Exemples d'utilisation:
Pour exécuter walkr
pour le répertoire actuel:
_walkr # You shouldn't use any argument,
walkr ./ # but you can use also this format
_
Pour exécuter walkr
pour n’importe quel répertoire enfant:
_walkr <directory name>
walkr ./<directory name>
walkr <directory name>/<sub directory>
_
Pour exécuter walkr
pour tout autre répertoire:
_walkr /full/path/to/<directory name>
_
Pour changer le nombre de fichiers à conserver (à _3
_ par exemple), utilisez ce format
_NFK=3 walkr
NFK=3 walkr /full/path/to/<directory name>
# etc.
_
5. Jouons avec le script walkr
:
Nous pouvons utiliser la commande touch file.name -d "1 hour ago"
pour créer un fichier vide daté d’une heure auparavant. Nous pouvons donc utiliser les commandes suivantes pour créer une structure de répertoire telle que présentée ici .
_mkdir -p ~/temp/dir{A..C} && cd ~/temp ;\
DEST=''; touch ${DEST}new_file{1..7} && touch ${DEST}older_file{1..7} -d "1 hour ago" && touch ${DEST}oldest_file{1..7} -d "2 hour ago" ;\
DEST='dirA/'; touch ${DEST}new_file{1..7} && touch ${DEST}older_file{1..7} -d "1 hour ago" && touch ${DEST}oldest_file{1..7} -d "2 hour ago" ;\
DEST='dirB/'; touch ${DEST}new_file{1..7} && touch ${DEST}older_file{1..7} -d "1 hour ago" && touch ${DEST}oldest_file{1..7} -d "2 hour ago" ;\
DEST='dirC/'; touch ${DEST}new_file{1..7} && touch ${DEST}older_file{1..7} -d "1 hour ago" && touch ${DEST}oldest_file{1..7} -d "2 hour ago"
_
Nous pouvons maintenant effectuer quelques tests:
Mise à jour de la fonctionnalité du script. Voici la version mise à jour du script ci-dessus:
_#!/bin/bash
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "$1" && ABS_PATH="${PWD}"
[[ -z "${2}" ]] && NFK='7' || NFK="$2" # Number of the files to be kept
[[ -z "${3}" ]] && REC='1' || REC="$3" # REC='1' - work recursively
[[ -z "${4}" ]] && VRB='1' || VRB="$4" # VRB='1' - work in verbose mode
file_operations() {
local IFS=$'\t\n' # Change the value of the Internal Field Separator locally
if [ "$VRB" == "1" ]
then # Verbose mode:
rm -v $(ls -lt | grep -Po '^-.*[0-9]{2}:[0-9]{2} \K.*' | tail -n +"$((NFK+1))") 2>/dev/null && printf " -from: '%s' \n" "$1" || echo "nothing to remove in: '$1'"
else # Quiet mode:
rm $(ls -lt | grep -Po '^-.*[0-9]{2}:[0-9]{2} \K.*' | tail -n +"$((NFK+1))") 2>/dev/null
fi
}
walk() {
# Change directory to the destination path and call the above function, pass $1 for the verbose mode
cd "$1" && file_operations "$1"
# If REC='1': Recursive mode -- Make the recursion; otherwise work on the curent level
if [ "$REC" == "1" ]; then for item in "$1"/*; do [[ -d "$item" ]] && walk "$item"; done; fi
}
walk "${ABS_PATH}"
_
Cette version du script peut gérer quelques variables d'entrée supplémentaires. Il a les modes silencieux et verbeux et peut fonctionner de manière non récursive.
Le format complet est:
_walkr '<destination path>' '<number of lines to be kept>' '<no recursion>' '<quiet>'
_
Où le contenu exact de _<no recursion>
_ et _<quiet>
_ est sans importance. Seules les variables d'entrée _$3
_ et _$4
_ ne doivent pas être vides pour que le comportement par défaut soit écrasé.