rimuovere i file più vecchi


9

Sto cercando di eliminare i vecchi file dalla directory e lasciare solo 3 file più recenti.

cd /home/user1/test

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

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

done

qualcosa non va nell'affermazione condizionale.

Risposte:


9

Se si desidera eseguire il loop dei file, non utilizzare mails *. tl; dr Ci sono molte situazioni in cui finiresti per cancellare il file sbagliato, o anche tutti i file.

Detto questo, sfortunatamente questa è una cosa difficile da fare proprio in Bash. C'è una risposta funzionante a una domanda duplicata mia ancora più vecchiafind_date_sorted che puoi usare con piccole modifiche:

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

* Senza offesa, ho usato anche lsprima. Ma non è davvero sicuro.

Modifica: Nuovofind_date_sorted con test unitari.


Secondo, la parte sul non analizzare ls. Anche la sceneggiatura è ordinata ma penso che potrebbe essere fatta in una sola
riga

Bene, puoi sempre compattare il codice Bash in una
riga

2
Se posso rubare senza pietà un'idea da @ Peter.O, prova ((++counter>3))come test. È piacevolmente succinto. Per quanto riguarda gli oneliners: se la brevità è una preoccupazione avvolgere il codice in una funzione, non preoccuparti.
Sorpigal,

Scorciatoia @Sorpigal Neat
l0b0

5

Per eliminare tutti tranne i 3 file più recenti utilizzando un zsh glob, è possibile utilizzare Om(maiuscola O) per ordinare i file dal più vecchio al più recente e un pedice per acquisire i file desiderati.

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

Altri esempi:

# 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])

5

Il metodo di gran lunga più semplice è usare zsh e le sue qualificazioni glob : Omordinare in ordine decrescente di età (ovvero prima i più vecchi) e [1,3]conservare solo le prime tre partite.

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

Vedi anche Come filtrare un glob in zsh per altri esempi.

E segui i consigli di l0b0 : il tuo codice si spezzerà in modo orribile se hai nomi di file che contengono caratteri speciali della shell.


Woa woa tenere il treno, è davvero una soluzione completa in 1 linea?
MetaGuru,

2
@Ryan Questo è zsh per te.
Gilles 'SO- smetti di essere malvagio'

1

È possibile utilizzare la seguente funzione per ottenere il file più recente in una directory:

newest_in() 
{ 
    local newest=$1

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

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

Dagli un set diverso di file sostituendo il file più recente dopo ogni iterazione.

Suggerimento: se si tiene il set iniziale di file in un array chiamato "$ {files [@]}", quindi salvare l'indice del file più recente trovato e unset 'files[index]'prima della successiva iterazione.

Uso: newest_in [set of files/directories]

Uscita campione:

[rany$] newest_in ./*
foo.txt
[rany$]

-1

Innanzitutto, l' -Ropzione è per la ricorsione, che probabilmente non è quello che vuoi - che cercherà anche in tutte le sottodirectory. In secondo luogo, l' <operatore (quando non viene visto come reindirizzamento) è per il confronto delle stringhe. Probabilmente vuoi -lt. Provare:

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

Ma userei trovare qui:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]

Entrambi falliranno se uno o più nomi di file contengono '$ \ n'.
Rany Albeg Wein,

-1

So che è un peccato analizzare ls, ma che dire di questo:

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

Un test rapido con 5 file vuoti:

$ >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

Questo fallirà per due motivi: analisi lsdell'output e utilizzo finde xargsinsieme nel modo sbagliato. Se si combinano finde xargsvi consiglio di utilizzare finds -print0e di conseguenza xargss -Oopzioni. Leggi Utilizzando Ricerca per ulteriori informazioni su questo argomento. Potresti anche dare un'occhiata e leggere perché analizzare Psing è molto male.
Rany Albeg Wein,

-2

Questo one-liner fa tutto ciò che penso:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"

ls è uno strumento per guardare interattivamente le informazioni sui file. Il suo output è formattato per gli umani e causerà bug negli script. Usa globs o trova invece. Capisci perché: mywiki.wooledge.org/ParsingLs
Rany Albeg Wein

-2

Ecco una soluzione:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)

1
@bakbak ls è uno strumento per guardare interattivamente le informazioni sui file. Il suo output è formattato per gli umani e causerà bug negli script. Guarda qui per capire il perché . Specificamente parlando della tua risposta: questa si interromperà se uno o più file contengono un carattere $ '\ n'. Inoltre, la sostituzione dei comandi (ovvero $ (...)) manca di virgolette doppie, il che fa apparire un altro argomento importante: la divisione delle parole !
Rany Albeg Wein,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.