Question: Comment effacez-vous tous les fichiers d'un répertoire sauf le plus récent des 3?
Trouver les 3 derniers fichiers est simple:
ls -t | head -3
Mais je dois trouver tous les fichiers sauf les 3 plus récents. Comment puis-je faire, et comment puis-je supprimer ces fichiers dans la même ligne sans créer une boucle for inutile pour cela?
J'utilise Debian Wheezy et les scripts bash pour cela.
Ceci listera tous les fichiers sauf les trois plus récents:
ls -t | tail -n +4
Cela supprimera ces fichiers:
ls -t | tail -n +4 | xargs rm --
Cela listera aussi les fichiers de points:
ls -At | tail -n +4
et supprimer avec les fichiers de points:
ls -At | tail -n +4 | xargs rm --
Attention, l'analyse ls
peut être dangereuse lorsque les noms de fichiers contiennent des caractères amusants tels que des lignes ou des espaces. Si vous êtes certain que vos noms de fichiers ne contiennent pas de caractères amusants, l'analyse ls
est relativement sûre, et encore plus s'il s'agit d'un script unique.
Si vous développez un script pour un usage répété, vous ne devez certainement pas analyser la sortie de ls
et utiliser les méthodes décrites ici: http://mywiki.wooledge.org/ParsingLs
Ce qui suit semble un peu compliqué, mais il est très prudent d’être correct, même avec des noms de fichiers inhabituels ou intentionnellement malveillants. Malheureusement, cela nécessite des outils GNU:
count=0
while IFS= read -r -d ' ' && IFS= read -r -d '' filename; do
(( ++count > 3 )) && printf '%s\0' "$filename"
done < <(find . -maxdepth 1 -type f -printf '%T@ %P\0' | sort -g -z) \
| xargs -0 rm -f --
Expliquant comment cela fonctionne:
<mtime> <filename><NUL>
pour chaque fichier du répertoire en cours.sort -g -z
effectue un tri numérique général (virgule flottante, par opposition à un entier) basé sur la première colonne (fois) avec les lignes séparées par des NUL.read
de la boucle while
supprime le paramètre mtime (n'est plus nécessaire une fois que sort
est terminé).read
dans la boucle while
lit le nom du fichier (jusqu'à la NUL).xargs -0
ajoute ensuite ce nom de fichier dans la liste argv qu'il collecte pour appeler rm
avec.ls -t | tail -n +4 | xargs -I {} rm {}
Si vous voulez un 1 liner
C'est une combinaison des réponses de Ceving et d'Anubhava… Les deux solutions ne fonctionnent pas pour moi. Parce que je recherchais un script qui devrait être exécuté quotidiennement pour sauvegarder des fichiers dans une archive, je voulais éviter les problèmes avec ls
(quelqu'un aurait pu enregistrer un fichier de nom amusant dans mon dossier de sauvegarde). J'ai donc modifié les solutions mentionnées pour répondre à mes besoins. La solution de Ceving supprime les trois fichiers les plus récents - pas ce dont j'avais besoin et on m'a demandé.
Ma solution supprime tous les fichiers, sauf les trois fichiers les plus récents.
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
head -n -3 |
cut -d $'\t' -f 2- |
xargs rm
Quelques explications:
find
liste tous les fichiers (pas les répertoires) du dossier actuel. Ils sont imprimés avec des horodatages.sort
trie les lignes en fonction de l'horodatage (la plus ancienne en haut).head
imprime les lignes du haut, jusqu'aux 3 dernières lignes.cut
supprime les horodatages.xargs
exécute rm
pour chaque fichier sélectionné.
A vous de vérifier ma solution:
(
touch -d "6 days ago" test_6_days_old
touch -d "7 days ago" test_7_days_old
touch -d "8 days ago" test_8_days_old
touch -d "9 days ago" test_9_days_old
touch -d "10 days ago" test_10_days_old
)
Cela crée 5 fichiers avec des horodatages différents dans le dossier actuel. Exécutez ceci en premier et le code de suppression pour tester le code.
En zsh:
rm /files/to/delete/*(Om[1,-4])
Si vous souhaitez inclure dotfiles , remplacez la partie entre parenthèses par (Om[1,-4]D)
.
Je pense que cela fonctionne correctement avec des caractères arbitraires dans les noms de fichiers (juste vérifié avec newline).
Explication: Les parenthèses contiennent des qualificatifs de Glob. O
signifie "ordre par, décroissant", m
signifie mtime (voir man zshexpn
pour d'autres clés de tri - grande page de manuel; recherchez "être trié"). [1,-4]
renvoie uniquement les correspondances à l'index basé sur une base 1 à (last + 1 - 4) (notez le -4
pour supprimer tout sauf 3).
N'utilisez pas ls -t
car il est dangereux pour les noms de fichiers pouvant contenir des espaces ou des caractères globaux spéciaux.
Vous pouvez le faire en utilisant tous les utilitaires basés sur gnu
pour supprimer tous les fichiers sauf le plus récent dans le répertoire actuel:
find . -maxdepth 1 -type f -printf '%T@\t%p\0' |
sort -z -nrk1 |
tail -z -n +4 |
cut -z -f2- |
xargs -0 rm -f --
Ceci utilise find
au lieu de ls
avec une transformation Schwartzian .
find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-
find
recherche les fichiers et les décore avec un horodatage et utilise la tabulatrice pour séparer les deux valeurs. sort
divise l'entrée par la tabulatrice et effectue un tri numérique général qui trie correctement les nombres à virgule flottante. tail
devrait être évident et cut
undecorates.
Le problème avec les décorations en général est de trouver un délimiteur approprié, qui ne fait pas partie de l’entrée, les noms de fichiers. Cette réponse utilise le caractère NULL.
ls -t | tail -n +4 | xargs -I {} rm {}
La réponse de Michael Ballent fonctionne mieux comme
ls -t | tail -n +4 | xargs rm --
jetez-moi une erreur si j'ai moins de 3 fichiers