usuń najstarsze pliki

9

Próbuję usunąć stare pliki z katalogu i zostawić tylko 3 najnowsze pliki.

cd /home/user1/test

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

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

done

coś jest nie tak z instrukcją warunkową.

d3vil0
źródło

Odpowiedzi:

9

Jeśli chcesz zapętlać pliki, nigdy nie używajls *. tl; dr Istnieje wiele sytuacji, w których możesz usunąć niewłaściwy plik, a nawet wszystkie pliki.

To powiedziawszy, niestety jest to podstępna rzecz, którą należy zrobić dobrze w Bash. Jest to odpowiedź na pracę nad pomocą duplikatu pytanie mój nawet starszefind_date_sorted , które można używać z małymi modyfikacjami:

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

* Bez przestępstw - użyłem też lswcześniej. Ale to naprawdę nie jest bezpieczne.

Edycja: Nowośćfind_date_sorted z testami jednostkowymi.

l0b0
źródło
Popieram część o nie analizowaniu ls. Również skrypt jest fajny, ale myślę, że można to zrobić w jednej
linijce
Cóż, zawsze możesz spakować kod Bash do jednej
linijki
2
Jeśli mogę bezlitośnie ukraść pomysł @ Peter.O, spróbuj ((++counter>3))jako swój test. Jest ładnie zwięzły. Jeśli chodzi o onelinerów: jeśli zwięzłość jest problemem, zawiń kod w funkcji, nie martw się o to.
Sorpigal,
@Sorpigal Neat skrót
l0b0
5

Aby usunąć wszystkie oprócz 3 najnowszych plików za pomocą globu zsh, możesz użyć Om(wielkich O) do sortowania plików od najstarszych do najnowszych oraz indeksu dolnego do przechwycenia żądanych plików.

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

Inne przykłady:

# 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
źródło
5

Zdecydowanie najłatwiejszą metodą jest użycie zsh i jego globalnych kwalifikatorów : Omsortowanie według malejącego wieku (tj. Najpierw najstarsze) i [1,3]zachowanie tylko trzech pierwszych dopasowań.

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

Zobacz także Jak filtrować glob w Zsh, aby uzyskać więcej przykładów.

I postępuj zgodnie z radą L0B0 : Twój kod będzie strasznie pękał, jeśli będziesz mieć nazwy plików zawierające znaki specjalne powłoki.

Gilles „SO- przestań być zły”
źródło
Woa woa trzyma pociąg, czy to naprawdę kompletne rozwiązanie w 1 linii?
MetaGuru,
2
@Ryan To zsh dla ciebie.
Gilles „SO- przestań być zły”
1

Aby pobrać najnowszy plik z katalogu, możesz użyć następującej funkcji:

newest_in() 
{ 
    local newest=$1

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

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

Daj mu inny zestaw plików, usuwając najnowszy plik po każdej iteracji.

Wskazówka: Jeśli trzymasz początkowy zestaw plików w tablicy o nazwie „$ {files [@]}”, zapisz indeks znalezionego najnowszego pliku i unset 'files[index]'przed następną iteracją.

Stosowanie: newest_in [set of files/directories]

Przykładowe dane wyjściowe:

[rany$] newest_in ./*
foo.txt
[rany$]
Rany Albeg Wein
źródło
-1

Po pierwsze, -Ropcja dotyczy rekurencji, która prawdopodobnie nie jest tym, czego chcesz - będzie ona również wyszukiwać we wszystkich podkatalogach. Po drugie, <operator (gdy nie jest postrzegany jako przekierowanie) służy do porównywania ciągów. Prawdopodobnie chcesz -lt. Próbować:

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

Ale skorzystałbym z find tutaj:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]
Arcege
źródło
Oba zawiodą, jeśli co najmniej jedna nazwa pliku zawiera „$ \ n”.
Rany Albeg Wein
-1

Wiem, że parsowanie jest grzechemls , ale co z tym:

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

Szybki test z 5 pustymi plikami:

$ >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
źródło
Ten zakończy się niepowodzeniem z dwóch powodów - parsowania lsdanych wyjściowych oraz niewłaściwego użycia findi xargsrazem. Jeśli połączysz findi xargspolecam użyć opcji finds -print0i odpowiednio xargss -O. Przeczytaj o używaniu Znajdź, aby uzyskać więcej informacji na temat. Możesz także rzucić okiem i przeczytać, dlaczego Parsing ls jest bardzo zły.
Rany Albeg Wein
-2

Ten jednowarstwowy robi wszystko, co myślę:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"
Salwa
źródło
ls to narzędzie do interaktywnego przeglądania informacji o plikach. Jego dane wyjściowe są sformatowane dla ludzi i będą powodować błędy w skryptach. Zamiast tego użyj globów lub znajdź. Dowiedz się,
Rany Albeg Wein
-2

Oto jedno rozwiązanie:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)
babak
źródło
1
@bakbak ls to narzędzie do interaktywnego przeglądania informacji o plikach. Jego dane wyjściowe są sformatowane dla ludzi i będą powodować błędy w skryptach. Zajrzyj tutaj, aby zrozumieć, dlaczego . Mówiąc konkretnie o twojej odpowiedzi - ta ulegnie awarii, jeśli jeden lub więcej plików zawiera znak $ '\ n'. Ponadto w poleceniu Podstawienie (tj. $ (...) brakuje podwójnych cudzysłowów, co porusza inny ważny temat - Podział słów !
Rany Albeg Wein