Domanda: Come si eliminano tutti i file in una directory tranne i più recenti 3?
Trovare i nuovi 3 file è semplice:
ls -t | head -3
Ma ho bisogno di trovare tutti i file tranne i più recenti 3 file. Come faccio a farlo, e come faccio a eliminare questi file nella stessa riga senza fare un loop inutile per quello?
Sto usando Debian Wheezy e gli script di bash per questo.
Questo elencherà tutti i file tranne i tre più recenti:
ls -t | tail -n +4
Questo cancellerà quei file:
ls -t | tail -n +4 | xargs rm --
Questo elencherà anche i dotfile:
ls -At | tail -n +4
ed elimina con dotfiles:
ls -At | tail -n +4 | xargs rm --
Ma attenzione: l'analisi di ls
può essere pericolosa quando i nomi dei file contengono caratteri divertenti come le nuove o gli spazi. Se si è certi che i nomi dei file non contengano caratteri divertenti, l'analisi di ls
è abbastanza sicura, ancor più se si tratta di uno script solo una volta.
Se stai sviluppando uno script per uso ripetuto, non dovresti assolutamente analizzare l'output di ls
e utilizzare i metodi descritti qui: http://mywiki.wooledge.org/ParsingLs
Quanto segue sembra un po 'complicato, ma è molto prudente per essere corretto, anche con nomi di file insoliti o intenzionalmente dannosi. Sfortunatamente, richiede GNU strumenti:
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 '%[email protected] %P\0' | sort -g -z) \
| xargs -0 rm -f --
Spiegando come funziona:
<mtime> <filename><NUL>
per ogni file nella directory corrente.sort -g -z
esegue un ordinamento numerico generale (a virgola mobile, anziché intero) basato sulla prima colonna (volte) con le righe separate da NUL.read
nel ciclo while
rimuove il mtime (non più necessario dopo che sort
è terminato).read
nel ciclo while
legge il nome del file (in esecuzione fino al NUL).xargs -0
quindi aggiunge quel nome di file all'elenco di argv che sta raccogliendo per invocare rm
con.ls -t | tail -n +4 | xargs -I {} rm {}
Se vuoi un 1 liner
Questa è una combinazione di risposta del ceving e di anubhava. Entrambe le soluzioni non funzionano per me. Poiché stavo cercando uno script che dovrebbe essere eseguito ogni giorno per il backup dei file in un archivio, volevo evitare problemi con ls
(qualcuno avrebbe potuto salvare qualche divertente nome file nella mia cartella di salvataggio). Così ho modificato le soluzioni citate per adattarle alle mie esigenze. La soluzzione di Ceving cancella i tre file più recenti, non quello di cui avevo bisogno e mi è stato chiesto.
La mia soluzione cancella tutti i file, tranne i tre file più recenti.
find . -type f -printf '%[email protected]\t%p\n' |
sort -t $'\t' -g |
head -n -3 |
cut -d $'\t' -f 2- |
xargs rm
Qualche spiegazione:
find
elenca tutti i file (non le directory) nella cartella corrente. Sono stampati con timestamp.sort
ordina le righe in base al timestamp (più vecchio in alto).head
stampa le prime righe, fino alle ultime 3 righe.cut
rimuove i timestamp.xargs
esegue rm
per ogni file selezionato.
Per verificare la mia soluzione:
(
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
)
Questo crea 5 file con data e ora differenti nella cartella corrente. Esegui prima questo e il codice per l'eliminazione per testare il codice.
In zsh:
rm /files/to/delete/*(Om[1,-4])
Se si desidera includere dotfile , sostituire la parte tra parentesi con (Om[1,-4]D)
.
Penso che funzioni correttamente con caratteri arbitrari nei nomi dei file (appena controllato con newline).
Spiegazione: le parentesi contengono i qualificatori Glob. O
significa "ordina per, decrescente", m
significa mtime (vedi man zshexpn
per le altre chiavi di ordinamento - manpage di grandi dimensioni; cerca "essere ordinato"). [1,-4]
restituisce solo le corrispondenze all'indice 1 basato su uno (last + 1 - 4) (notare -4
per l'eliminazione di tutti tranne 3).
Non utilizzare ls -t
in quanto non sicuro per i nomi di file che potrebbero contenere spazi bianchi o caratteri speciali glob.
Puoi farlo usando tutte le utility basate su gnu
per eliminare tutti i 3 file più nuovi nella directory corrente:
find . -maxdepth 1 -type f -printf '%[email protected]\t%p\0' |
sort -z -nrk1 |
tail -z -n +4 |
cut -z -f2- |
xargs -0 rm -f --
Questo usa find
invece di ls
con una trasformazione di Schwartzian .
find . -type f -printf '%[email protected]\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-
find
cerca i file e li decora con un timestamp e utilizza il tabulatore per separare i due valori. sort
divide l'input dal tabulatore ed esegue un ordinamento numerico generale, che ordina correttamente i numeri in virgola mobile. tail
dovrebbe essere ovvio e cut
undecorates.
Il problema con le decorazioni in generale è trovare un delimitatore adatto, che non fa parte dell'input, i nomi dei file. Questo answer usa il carattere NULL.
ls -t | tail -n +4 | xargs -I {} rm {}
La risposta di Michael Ballent funziona meglio come
ls -t | tail -n +4 | xargs rm --
lanciami errore se ho meno di 3 file