Jak rekurencyjnie znaleźć najnowszy zmodyfikowany plik w katalogu?

Odpowiedzi:

357
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

W przypadku wielkiego drzewa może być trudno sortzachować wszystko w pamięci.

%T@daje ci czas modyfikacji jak uniksowy znacznik czasu, sort -nsortuje numerycznie, tail -1pobiera ostatni wiersz (najwyższy znacznik czasu), cut -f2 -d" "odcina pierwsze pole (znacznik czasu) od wyniku.

Edycja: Tak jak -printfprawdopodobnie tylko GNU, tak samo użyteczne stat -cjest użycie . Chociaż można zrobić to samo na BSD, opcje formatowania są inne ( -f "%m %N"wydaje się)

I brakowało mi części liczby mnogiej; jeśli chcesz więcej niż ten ostatni plik, po prostu podbić argument ogon.

plundra
źródło
7
Jeśli kolejność ma znaczenie, możesz zmienić użycie sort -rn | head -3zamiast sort -n | tail -3. Jedna wersja podaje pliki od najstarszego do najnowszego, a druga od najnowszej do najstarszej.
Don Faulkner,
3
Miałem ogromny katalog (około dziesięciu tysięcy małych plików) i martwiłem się wydajnością, ale ... to polecenie zostało uruchomione w mniej niż sekundę! Świetnie, wielkie dzięki !!! :-)
lucaferrario,
2
„W przypadku dużego drzewa może być trudne zachowanie wszystkiego w pamięci”. sortutworzy pliki tymczasowe (w /tmp) zgodnie z potrzebami, więc nie sądzę, że to niepokoi.
Vladimir Panteleev
1
zmieniając go na: -printf '%T@ %Tb %Td %TY %p\n'da ci datownik (w razie potrzeby) (podobny do ls)
bshea
1
Uważam, że następujące wyniki są krótsze i bardziej zrozumiałe:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
snth
129

W odpowiedzi na odpowiedź @ plundra , oto wersja BSD i OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "
Emerson Farrugia
źródło
1
Czy BSD / OS X findobsługuje +zamiast tego \;? Ponieważ robi to to samo (przekazując wiele plików jako parametry), bez -print0 | xargs -0potoku.
DevSolar
Co zrobić, jeśli chcę uzyskać 5 lub n ostatnich plików zmodyfikowanych w kolejności malejącej?
khunshan,
@khunshan zmienić head -1sięhead -5
Emerson Farrugia
20

Zamiast sortować wyniki i przechowywać tylko te ostatnio zmodyfikowane, możesz użyć awk, aby wydrukować tylko ten z największym czasem modyfikacji (w czasie uniksowym):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Powinno to być szybszym sposobem rozwiązania problemu, jeśli liczba plików jest wystarczająco duża.

Użyłem znaku NUL (tj. „\ 0”), ponieważ teoretycznie nazwa pliku może zawierać dowolny znak (w tym spację i znak nowej linii), ale to.

Jeśli nie masz takich patologicznych nazw plików w systemie, możesz również użyć znaku nowej linii:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Ponadto działa to również w mawk.

marco
źródło
Można to łatwo dostosować, aby zachować trzy najnowsze.
Wstrzymano do odwołania.
1
To nie działa ze mawkstandardową alternatywą Debiana.
Jan
Nie, ale w takim przypadku możesz użyć znaku nowej linii, jeśli ci to nie przeszkadza;)
marco
10

Miałem problem ze znalezieniem ostatnio zmodyfikowanego pliku w systemie Solaris 10. Nie findma takiej printfopcji i statnie jest dostępny. Odkryłem następujące rozwiązanie, które działa dobrze dla mnie:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Aby wyświetlić również nazwę pliku, użyj

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Wyjaśnienie

  • find . -type f znajduje i wyświetla wszystkie pliki
  • sed 's/.*/"&"/' zawija nazwę ścieżki w cudzysłów, aby obsługiwać białe znaki
  • xargs ls -Ewysyła cytowaną ścieżkę do ls, -Eopcja zapewnia zwrot pełnego znacznika czasu (format rok-miesiąc-dzień godzina-minuta-sekundy-nanosekundy )
  • awk '{ print $6," ",$7 }' wyodrębnia tylko datę i godzinę
  • awk '{ print $6," ",$7," ",$9 }' wyodrębnia datę, godzinę i nazwę pliku
  • sort zwraca pliki posortowane według daty
  • tail -1 zwraca tylko ostatni zmodyfikowany plik
Florian Feldhaus
źródło
9

To wydaje się działać dobrze, nawet w podkatalogach:

find . -type f | xargs ls -ltr | tail -n 1

W przypadku zbyt wielu plików sprecyzuj wyszukiwanie.

mgratia
źródło
1
-lOpcja lswydaje się zbędne. Po prostu -trwydaje się wystarczająca.
Acumenus
6
Wygląda na to, że sortuje się według katalogu, więc niekoniecznie pokazuje najnowszy plik
Fabian Schmengler,
1
Jeśli w ścieżkach plików są spacje, lepiej:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Konserwacja okresowa
To nie znajduje dla mnie najnowszych plików.
K.-Michael Aye,
1
Pomyśl, że to się psuje, jeśli w nazwach plików są spacje
waferthin
7

Pokazuje najnowszy plik ze znacznikiem czasu czytelnym dla człowieka:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Wynik wygląda następująco:

2015-10-06 11:30: +0200 ./foo/bar.txt

Aby wyświetlić więcej plików, zamień -n1na wyższy numer

Fabian Schmengler
źródło
5

Cały czas używam czegoś podobnego, a także listy najlepszych ostatnio modyfikowanych plików. W przypadku dużych drzew katalogów może być znacznie szybsze, aby uniknąć sortowania . W przypadku pierwszego najlepiej zmodyfikowanego pliku:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

W katalogu zawierającym 1,7 miliona plików otrzymuję najnowszy z 3,4 s, przyspieszenie 7,5x w stosunku do rozwiązania 25,5s za pomocą sortowania.

Pierre D.
źródło
Bardzo fajnie: właśnie wymieniłem ostatni wydruk na: system ("ls -l $ f") if eof (), aby również dobrze widzieć datę.
Martin T.
@MartinT. : świetnie i nie ma za co. Dziwne jest dla mnie, że ludzie mają instynkt sortowania rzeczy (O (n log n)), gdy dostępna jest metoda O (n). Wydaje się, że jest to jedyna odpowiedź pozwalająca uniknąć rodzaju. BTW, celem polecenia, które zasugerowałem, jest po prostu znalezienie ścieżki do najnowszego pliku. Możesz aliasować polecenie w swojej powłoce (np. Jako lastfile), a następnie możesz robić, co chcesz z wynikiem, na przykład ls -l $(lastfile .), lub open $(lastfile .)(na komputerze Mac) itp.
Pierre D
Och, stoję skorygowany: poniżej widzę inną odpowiedź (@marco). +1.
Pierre D,
4

To daje posortowaną listę:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Odwróć kolejność, umieszczając „-r” w poleceniu sortowania. Jeśli chcesz tylko nazwy plików, wstaw „awk” {print 11 USD} „|” przed „| głowa'

Karlo
źródło
3

W Ubuntu 13 robi to, może odrobinę szybciej, ponieważ odwraca sortowanie i używa „głowy” zamiast „ogona”, co zmniejsza pracę. Aby wyświetlić 11 najnowszych plików w drzewie:

odnaleźć . -type f -printf '% T @% p \ n' | sort -n -r | głowa -11 | cut -f2- -d "" | sed -e 's, ^. / ,,' | xargs ls -U -l

Daje to pełną listę ls bez ponownego sortowania i pomija denerwujące „./”, które „find” umieszcza na każdej nazwie pliku.

Lub jako funkcja bash:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

Mimo to większość pracy została wykonana przy użyciu oryginalnego rozwiązania Plundry. Dzięki plundra.

RickyS
źródło
3

Napotkałem ten sam problem. Muszę znaleźć najnowszy plik rekurencyjnie. znalezienie zajęło około 50 minut.

Oto mały skrypt, aby zrobić to szybciej:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

Jest to funkcja rekurencyjna, która pobiera najnowszą zmodyfikowaną pozycję katalogu. Jeśli ten element jest katalogiem, funkcja jest wywoływana rekurencyjnie i szuka w tym katalogu itp.

AnatomicJC
źródło
3

Uważam, że następujące wyniki są krótsze i bardziej zrozumiałe:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

Biorąc pod uwagę stałą długość znormalizowanych formatów danych ISO, sortowanie leksykograficzne jest w porządku i nie potrzebujemy -nopcji sortowania.

Jeśli chcesz ponownie usunąć znaczniki czasu, możesz użyć:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '
snth
źródło
2

Jeśli uruchamianie statkażdego pliku osobno jest spowolnione, możesz użyć go xargsdo przyspieszenia:

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 
Mattias Wadman
źródło
2

To rekurencyjnie zmienia czas modyfikacji wszystkich katalogów w bieżącym katalogu na najnowszy plik w każdym katalogu:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done
rwhirn
źródło
1
Psunie się źle, jeśli katalog zawiera spacje - należy ustawić IFS i użyć cudzysłowów: IFS = $ '\ n'; dla katalogu w $ (find ./ -typ d); wykonaj echo „$ dir”; znajdź „$ dir” -type f -printf '% T @ "% p" \ n' | sort -n | ogon -1 | cut -f2- -d "" | xargs -I {} touch -r {} „$ dir”; Gotowe;
Andy Lee Robinson
2

Ta prosta cli będzie również działać:

ls -1t | head -1

Możesz zmienić -1 na liczbę plików, które chcesz wyświetlić

Ankit Zalani
źródło
10
Nie, nie będzie, ponieważ nie jest rekurencyjny.
arataj
1

Uznałem powyższe polecenie za przydatne, ale w moim przypadku musiałem zobaczyć datę i godzinę pliku, a także miałem problem z kilkoma plikami, które mają spacje w nazwach. Oto moje działające rozwiązanie.

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l
Roger Cable
źródło
1

Następujące polecenie działało w systemie Solaris:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 
RahulM
źródło
1

Ignorowanie ukrytych plików - z ładnym i szybkim znacznikiem czasu

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

Wynik

Dobrze radzi sobie ze spacjami w nazwach plików - nie należy ich używać!

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

Więcej

Więcej find obfitości po linku.

Serge Stroobandt
źródło
1

Aby wyszukać pliki w katalogu / target_directory i wszystkich jego podkatalogach, które zostały zmodyfikowane w ciągu ostatnich 60 minut:

$ find /target_directory -type f -mmin -60

Aby znaleźć ostatnio zmodyfikowane pliki, posortowane w odwrotnej kolejności czasu aktualizacji (tj. Najpierw najnowsze zaktualizowane pliki):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r
akash
źródło
0

Wolę ten, jest krótszy:

find . -type f -print0|xargs -0 ls -drt|tail -n 1
użytkownik3295940
źródło
0

Napisałem pypi / github na to pytanie, ponieważ potrzebowałem również rozwiązania.

https://github.com/bucknerns/logtail

Zainstalować:

pip install logtail

Zastosowanie: ogony zmieniły pliki

logtail <log dir> [<glob match: default=*.log>]

Użycie 2: Otwiera ostatnio zmieniony plik w edytorze

editlatest <log dir> [<glob match: default=*.log>]
Nathan Buckner
źródło