supprimer les fichiers les plus anciens

9

J'essaie de supprimer les anciens fichiers du répertoire et de ne laisser que 3 fichiers les plus récents.

cd /home/user1/test

while [ `ls -lAR | grep ^- | wc -l` < 3 ] ; do

    rm `ls -t1 /home/user/test | tail -1`
    echo " - - - "

done

quelque chose ne va pas avec la déclaration conditionnelle.

d3vil0
la source

Réponses:

9

Si vous souhaitez faire une boucle sur des fichiers, n'utilisez jamaisls *. tl; dr Il y a beaucoup de situations où vous finiriez par supprimer le mauvais fichier, ou même tous les fichiers.

Cela dit, malheureusement, c'est une chose délicate à faire correctement à Bash. Il y a une réponse de travail à une question en double, encore plus ancienne,find_date_sorted que vous pouvez utiliser avec de petites modifications:

counter=0
while IFS= read -r -d '' -u 9
do
    let ++counter
    if [[ counter -gt 3 ]]
    then
        path="${REPLY#* }" # Remove the modification time
        echo -e "$path" # Test
        # rm -v -- "$path" # Uncomment when you're sure it works
    fi
done 9< <(find . -mindepth 1 -type f -printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz) # Find and sort by date, newest first

* Les gars sans infraction - je l'ai également utilisé lsavant. Mais ce n'est vraiment pas sûr.

Edit: Nouveaufind_date_sorted avec des tests unitaires.

l0b0
la source
J'appuie la partie sur ne pas analyser ls. De plus, le script est soigné mais je pense que cela pourrait être fait dans une seule ligne, laissez-moi vérifier ...
rahmu
Eh bien, vous pouvez toujours compacter le code Bash en une seule ligne, mais le problème est de savoir s'il sera lisible :)
l0b0
2
Si je peux voler sans pitié une idée de @ Peter.O, essayez ((++counter>3))comme test. C'est bien succinct. Quant aux oneliners: si la brièveté est un problème, enveloppez le code dans une fonction, alors ne vous inquiétez pas.
Sorpigal
@Sorpigal Neat shortcut
l0b0
5

Pour supprimer tous les fichiers, à l'exception des 3 plus récents, à l'aide d'un zsh glob, vous pouvez utiliser Om(majuscule O) pour trier les fichiers du plus ancien au plus récent et un indice pour récupérer les fichiers que vous souhaitez.

rm ./*(Om[1,-4])
#    | ||||  ` stop at the 4th to the last file (leaving out the 3 newest)
#    | |||` start with first file (oldest in this case)
#    | ||` subscript to pick one or a range of files
#    | |` look at modified time
#    | ` sort in descending order
#    ` start by looking at all files

Autres exemples:

# delete oldest file (both do the same thing)
rm ./*(Om[1])
rm ./*(om[-1])

# delete oldest two files
rm ./*(Om[1,2])

# delete everything but the oldest file
rm ./*(om[1,-2])
Mario Lopez
la source
5

La méthode de loin la plus simple consiste à utiliser zsh et ses qualificatifs glob : Ompour trier par âge décroissant (c'est-à-dire le plus ancien en premier) et [1,3]pour ne conserver que les trois premières correspondances.

rm ./*(Om[1,3])

Voir aussi Comment filtrer un glob dans zsh pour plus d'exemples.

Et suivez les conseils de l0b0 : votre code se cassera horriblement si vous avez des noms de fichiers contenant des caractères spéciaux shell.

Gilles 'SO- arrête d'être méchant'
la source
Woa woa tient le train, est-ce vraiment une solution complète en 1 ligne?
MetaGuru
2
@Ryan C'est zsh pour vous.
Gilles 'SO- arrête d'être méchant'
1

Vous pouvez utiliser la fonction suivante pour obtenir le fichier le plus récent dans un répertoire:

newest_in() 
{ 
    local newest=$1

    for f;do [[ $f -nt $newest ]] && newest="$f"; done;

    printf '%s\n' "$newest"
}

Donnez-lui un ensemble de fichiers différent en supprimant le fichier le plus récent après chaque itération.

Conseil: Si vous conservez l'ensemble initial de fichiers dans un tableau appelé "$ {files [@]}", enregistrez l'index du fichier le plus récent trouvé et unset 'files[index]'avant l'itération suivante.

Usage: newest_in [set of files/directories]

Exemple de sortie:

[rany$] newest_in ./*
foo.txt
[rany$]
Rany Albeg Wein
la source
-1

Tout d'abord, l' -Roption est pour la récursivité, ce qui n'est probablement pas ce que vous voulez - qui recherchera également dans tous les sous-répertoires. Deuxièmement, l' <opérateur (lorsqu'il n'est pas considéré comme une redirection) sert à la comparaison de chaînes. Tu veux probablement -lt. Essayer:

while [ `ls -1A | grep ^- | wc -l` -lt 3 ]

Mais j'utiliserais trouver ici:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]
Arcege
la source
Les deux échoueront si un ou plusieurs des noms de fichiers contiennent un «$ \ n».
Rany Albeg Wein
-1

Je sais que c'est un péché à analyser ls, mais qu'en est-il:

find . -type f -maxdepth 1 | xargs ls -ltr | sed '1,3d' | awk '{print $9}' | xargs rm

Un test rapide avec 5 fichiers vides:

$ >1
$ >2
$ >3
$ >4
$ >5
$ find . -type f -maxdepth 1 | xargs ls -lt | sed '1,3d' | awk '{print $9}' | xargs rm
$ ls -1
3
4
5
Rudolf Adamkovic
la source
Celui-ci échouera pour deux raisons: analyser la lssortie et utiliser findet xargsensemble de la mauvaise manière. Si vous combinez findet xargsje vous recommande d'utiliser les options finds -print0et en conséquence xargss -O. Pour en savoir plus sur le sujet, lisez l'article Utilisation de la recherche . Vous voudrez peut-être également jeter un coup d'œil et découvrir pourquoi l' analyse ls est très mauvaise.
Rany Albeg Wein
-2

Ce one-liner fait tout ce que je pense:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"
Salve
la source
ls est un outil pour consulter de manière interactive les informations sur les fichiers. Sa sortie est formatée pour les humains et provoquera des bugs dans les scripts. Utilisez des globes ou recherchez plutôt. Comprenez pourquoi: mywiki.wooledge.org/ParsingLs
Rany Albeg Wein
-2

Voici une solution:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)
babak
la source
1
@bakbak ls est un outil pour consulter de manière interactive les informations sur les fichiers. Sa sortie est formatée pour les humains et provoquera des bugs dans les scripts. Regardez ici pour comprendre pourquoi . Parlant spécifiquement de votre réponse - celle-ci se cassera si un ou plusieurs des fichiers contiennent un caractère $ '\ n'. De plus, la substitution de commande (c'est-à-dire $ (...)) manque de guillemets doubles, ce qui soulève un autre sujet important - le fractionnement de mots !
Rany Albeg Wein