2010-11-08 14 views
19

Powiel możliwe:
Delete all but the most recent X files in bashBash polecenie, aby usunąć wszystkie ale ostatnie 5 katalogów

Mam skrypt do tworzenia przyrostowych kopii zapasowych codziennie i muszę usunąć wszystkie kopie zapasowe, ale ostatnie 5.

Na przykład mam ten foldery:

 
drwxr-xr-x 4 root root 4096 Oct 29 01:10 2010-10-29 
drwxr-xr-x 4 root root 4096 Oct 30 01:10 2010-10-30 
drwxr-xr-x 4 root root 4096 Oct 31 01:10 2010-10-31 
drwxr-xr-x 4 root root 4096 Nov 1 01:10 2010-11-01 
drwxr-xr-x 4 root root 4096 Nov 2 01:10 2010-11-02 
drwxr-xr-x 4 root root 4096 Nov 3 01:10 2010-11-03 
drwxr-xr-x 4 root root 4096 Nov 4 01:10 2010-11-04 
drwxr-xr-x 4 root root 4096 Nov 5 01:10 2010-11-05 
drwxr-xr-x 4 root root 4096 Nov 6 01:10 2010-11-06 
drwxr-xr-x 4 root root 4096 Nov 7 01:10 2010-11-07 
drwxr-xr-x 4 root root 4096 Nov 8 01:10 2010-11-08 

I muszę zachować tylko ostatnie 5 katalogów i usunąć pozostałe. Po polecenie wykonać, muszę mieć tylko to:

 
drwxr-xr-x 4 root root 4096 Nov 4 01:10 2010-11-04 
drwxr-xr-x 4 root root 4096 Nov 5 01:10 2010-11-05 
drwxr-xr-x 4 root root 4096 Nov 6 01:10 2010-11-06 
drwxr-xr-x 4 root root 4096 Nov 7 01:10 2010-11-07 
drwxr-xr-x 4 root root 4096 Nov 8 01:10 2010-11-08 

nie muszę usunąć poprzednie 5 dni, muszę usunąć wszystko z wyjątkiem ostatnich 5 katalogów :)

Teraz używam :

find /backup/increment -maxdepth 1 -type d -mtime +5 -exec rm -rf {} \;

Ale muszę się do poprawy nie opiera się w czasie :)

EDIT: To jest przykład dla serwera, który zrobić kopie zapasowe wszystkich dni, ale muszę mieć skrypt, który usuwał wszystkie foldery wcześniejsze trwać 5, ponieważ mój komputer robić kopie zapasowe na 00:10 w nocy, ale nie wszystkie noce kopia zapasowa jest wykonywana, bo mój komputer nie działa we wszystkie dni, i muszę zawsze mieć ostatnie 5 kopie :)

+0

Jeśli to nie jest „oparty na czasie”, jaka jest twoja definicja „ostatnie 5”? –

+0

@dogbane dzięki, ale rozwiązanie @MartinStettner wydaje się być bardziej eleganckim rozwiązaniem :) – Lito

+0

@David Dodano komentarz w głównym poście. – Lito

Odpowiedz

32

użyć polecenia tail do drukowanych wierszy począwszy od linii n th (Option -n +N):

rm `ls -t | tail -n +6` 

ls -t wyprowadza bieżącego katalogu posortowane według czasu. tail -n +6 przyjmuje linie al zaczynające się od szóstej linii. Cytowanie za pomocą odsunięć powoduje podawanie wyniku potoku do polecenia rm.

starego rozwiązania, nie jest prawidłowe ...

użyć polecenia head, która drukuje pierwsze n linie jakiegoś wyjścia:

rm `ls -t1 | head -n 5` 

ls -t Wyjścia bieżący katalog posortowane według czasu . head -n 5 pobiera pięć pierwszych pozycji poprzedniego wyjścia. Cytowanie za pomocą odsunięć powoduje podawanie wyniku potoku do polecenia rm.

Spróbuj najpierw przed nałożeniem żyć dane :) ...

+1

Zamiast tego chciałbyś użyć ogona, dla * ostatnich * n linii. Ale tak, to rozwiązanie jest o wiele prostsze i lepsze niż moje. :) –

+1

Co powiecie na: 'rm $ (ls | sort -r | sed 1,5d)'; wymień nazwiska w porządku daty; posortuj je w kolejności odwrotnej (ostatnio najnowsze); usuń pierwsze pięć linii; usuń wszystko, co zostało. –

+0

@Max: Dzięki za wskazanie mojego błędu. Na szczęście istnieje opcja + N do "tail" (której nie znałem), więc możemy uzyskać wszystkie linie *, ale pierwsze n *. – MartinStettner

0

tworzą dwie atrapy pliki z początkiem a datą końcową

touch -t 1010290000 before 
touch -t 2011042359 after 

wybrać wszystkie pliki pomiędzy 2 pliki obojętne i "rm -rf" wynik:

find . -newer before \! -newer after -exec rm -rf {} \; 
+0

Jakieś bardziej eleganckie rozwiązanie? :) – Lito

+0

Rozwiązanie nie będzie oparte na dacie/czasie :) – Lito

1

Pierwsza rzecz, która przyszła w moim umyśle. Nie jest elegancka:

a=0; 
for i in `ls -t`; 
do 
    a=`expr $a + 1`; 
    if [ $a -gt 5 ]; then 
      echo "removing $i"; 
      rm -rf $i 
    fi; 
done 
+0

To nie jest eleganckie, ale jest możliwe rozwiązanie :) – Lito

0

ls -tr | perl -ne '{@files = <>; print @files [0 .. $ # files-5]} '| xargs -N1 echo rm -rf

by usunąć echo przed -rf rm aby zmusić go do pracy.

0

Sztuką będzie opcja -t do ls, który sortuje według czasu modyfikacji, od najnowszych do najstarszych.

Naprawdę naiwne rozwiązanie, używając pliku tymczasowego, może przejść w ten sposób:

ls -t > /tmp/file_list 
num_files_to_keep=5 
# wc -l gets the line count of a file 
# first word of wc output is the actual line count, and that's all we need, so 
# delete everything after the space. 
num_files=`wc -l /tmp/file_list | sed "s/ .*//"` 
#if appropriate you should add a check for num_files < num_files_to_keep 
num_files_to_delete=$(($num_files - $num_files_to_keep)) 
rm `tail -n $num_files_to_delete /tmp/file_list` 
Powiązane problemy