Znajdź najnowszy plik według daty modyfikacji

38

Jak chcę to zrobić, jeśli chcę znaleźć najnowszy plik (mtime) w (dużym) katalogu zawierającym podkatalogi?

Wiele postów, które znalazłem, sugeruje pewne odmiany ls -lt | head(zabawnie, wiele sugeruje, że ls -ltr | tailjest to ta sama, ale mniej wydajna), co jest w porządku, chyba że masz podkatalogi (ja tak).

Z drugiej strony możesz

find . -type f -exec ls -lt \{\} \+ | head

co z pewnością sprawdzi się w przypadku tylu plików, ile może określić jedno polecenie, tzn. jeśli masz duży katalog, -exec...\+wydasz osobne polecenia; dlatego każda grupa zostanie posortowana według lssiebie, ale nie według całego zestawu; dlatego głowa wybierze ostatni wpis z pierwszej partii.

Jakieś odpowiedzi?

Bogaty
źródło
przy okazji, nie potrzebujesz żadnego z tych ukośników odwrotnych.
enzotib
@enzotib: robisz ( \ + ), w przeciwnym razie dostajeszfind: missing argument to '-exec'
umów się
@arrange: Nie mam tego błędu, ponieważ +nie ma on znaczenia bash, więc nie ma potrzeby ucieczki.
enzotib
@enzotib: masz rację, mój błąd, przepraszam
umów się

Odpowiedzi:

46

Nie musisz powracać do poleceń zewnętrznych (as ls), ponieważ findmożesz zrobić wszystko, czego potrzebujesz, poprzez -printfakcję:

find /path -printf '%T+ %p\n' | sort -r | head
enzotib
źródło
1
Tak, wymyśliłem, find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1ale twoje rozwiązanie jest o wiele czystsze!
Rich
3
Dołącz, | cut -d ' ' -f2aby uzyskać tylko nazwę pliku
qwr
Możesz także wyciąć dane wyjściowe, headaby uwzględnić określoną liczbę wierszy. Potrzebowałem tylko pierwszej linii, więc użyłemhead -n 1
Timmah
8

Miałem dzisiaj podobny problem, ale zaatakowałem go bez find. Potrzebowałem czegoś krótkiego, co mogłem uruchomić, sshaby zwrócić ostatnio edytowany plik w moim katalogu domowym. Z grubsza to wymyśliłem:

ls -tp | grep -v /$ | head -1

-pOpcja lsdodaje końcowy ukośnik do katalogów, gdy grep -vlinie Usuwa kończące się ukośnik (aka wszystkie katalogi), oraz head -1ogranicza wyjście do jednego pliku.

Jest to znacznie mniej szczegółowe niż używanie, findjeśli wszystko, co chcesz zwrócić, to nazwa pliku.

Pat Regan
źródło
To nie obsługuje podkatalogów.
Clément
4

Jest to w moim systemie szybciej niż printf, choć nie rozumiem dlaczego

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head
zorganizować
źródło
Potwierdzam, że jest szybszy.
enzotib
Jeszcze jeden punkt, ... | sort -r | head -n1 | cut -d " " -f 4-jeśli chcesz uzyskać tylko nazwę pliku.
皞 皞
Właśnie znalazłem, że sort -rbędzie źle, jeśli nazwa pliku w wielu wierszach istnieje.
皞 皞
2

EDYCJA: Myślę, że ten post nie jest „szczególnie przydatny”, tak jak myślałem. To naprawdę szybkie rozwiązanie, które śledzi ostatnio zmodyfikowany plik (zamiast sortować całą listę plików):

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

Rozłożony na wiele linii dla przejrzystości wygląda następująco:

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

Koniec edycji


Niezbyt przydatny post, ale ponieważ „aranżacja” dotyczyła szybkości, pomyślałem, że się tym podzielę.

Rozwiązania arrange i enzotib obejmują wylistowanie wszystkich plików w katalogu wraz z ich mtimes, a następnie sortowanie. Jak wiadomo sortowanie nie jest konieczne, aby znaleźć maksimum. Znalezienie maksimum można wykonać w czasie liniowym, ale sortowanie zajmuje n log (n) czasu [Wiem, że różnica nie jest duża, ale nadal;)]. Nie mogę wymyślić dobrego sposobu na wdrożenie tego. [EDYCJA: Schludna (choć brudna) i szybka implementacja podana powyżej.]

Następna najlepsza rzecz - aby znaleźć ostatnio edytowany plik w katalogu, rekurencyjnie znajdź ostatnio edytowany plik w każdym podkatalogu poziomu 1. Niech ten plik reprezentuje podkatalog. Teraz posortuj pliki poziomu 1 wraz z przedstawicielami podkatalogów poziomu 1. Jeśli liczba plików poziomu 1 i podkatalogów każdego katalogu jest prawie stała, proces ten powinien być skalowany liniowo z całkowitą liczbą plików.

Oto, co wymyśliłem, aby to wdrożyć:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

Uruchomiłem to i dostałem mnóstwo find: findrecent: No such file or directorybłędów. Powód: -exec find działa w innej powłoce. Próbowałem zdefiniować findrecent w .bashrc, .xsessionrc, ale to nie pomogło [doceniłbym tutaj pomoc]. W końcu zdecydowałem się na wprowadzenie

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

w skrypcie wywoływanym findrecentw mojej ŚCIEŻCE, a następnie uruchamianym.

Uruchomiłem to, czekałem i czekałem bez wyjścia. Dla pewności nie miałem do czynienia z żadnymi nieskończonymi pętlami, do których zmodyfikowałem plik

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

i spróbowałem jeszcze raz. To działało - ale zajęło mi 1 minutę 35 sekund na moim folderze domowym - rozwiązania arrange i enzotib zajęły odpowiednio 1,69, 1,95 sekundy!

Tyle o wyższości O (n) nad O (n log (n))! Cholera, zadzwoń narzut! [A raczej narzut wywołania skryptu]

Ale ten skrypt skaluje się lepiej niż wcześniejsze rozwiązania i założę się, że będzie działał szybciej niż one w banku pamięci google; D

S Prasanth
źródło
2

Stosuj perlw połączeniu z find:

 find my_directory -type f -printf '%T@\t%p\n' | perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

Otrzymasz nazwę pliku z największą epoką == ostatni zmodyfikowany plik.

MUY Belgium
źródło
1

Nie jest to tak modne, ale można to również osiągnąć dzięki Midnight Commander : wyszukaj *, uporządkuj wynik, sortuj według czasu modyfikacji w odwrotnej kolejności.

Oczywiście jest to nieco wolniejsze niż find- mój katalog domowy, zawierający 922000 plików, został posortowany mcw ciągu prawie 14 minut, podczas gdy findspędził mniej niż 5 - ale są pewne zalety:

  • Prawdopodobnie spędziłbym dłużej niż różnicę 9 minut wymyślając odpowiednie wywołanie find :)

  • mniejsza szansa na błąd (zapomniałem podać -r do sortowania itp. - zacznij od nowa)

  • można grać z zestawem wyników, zmieniając kolejność sortowania itp. - bez ponownego zapytania plików.

  • możliwe jest wykonywanie operacji na plikach tylko na niektórych plikach z zestawu wyników - tj. sortuj według rozmiaru, usuń kilka dużych plików, które nie są potrzebne

Siergiej
źródło