Zmodyfikowano wyszukiwanie i sortowanie według systemów Unix / Linux

138

Jak mogę zrobić prosty, findktóry uporządkuje wyniki według najnowszych modyfikacji?

Oto bieżący, findktórego używam (robię ucieczkę powłoki w PHP, więc to jest powód dla zmiennych):

find '$dir' -name '$str'\* -print | head -10

Jak mogę zmienić to wyszukiwanie według ostatnio zmodyfikowanych? (Uwaga: nie chcę, aby sortował „po” wyszukiwaniu, ale raczej znajdował wyniki na podstawie tego, co zostało ostatnio zmodyfikowane).

Peter Mortensen
źródło
github.com/shadkam/recentmost zrobiłby to, co jest pożądane - ale trzeba je zbudować
user3392225

Odpowiedzi:

153

Użyj tego:

find . -printf "%T@ %Tc %p\n" | sort -n

printfargumenty od man find:

  • %Tk: Czas ostatniej modyfikacji pliku w formacie określonym przez k.

  • @: sekundy od 1 stycznia 1970 r., 00:00 GMT, z częścią ułamkową.

  • c: data i godzina ustawienia narodowego (sob. 04 12:02:33 EST 1989).

  • %p: Nazwa pliku.

użytkownik195696
źródło
5
+1 Bardzo przydatne, pierwsza odpowiedź na to pytanie, którą znalazłem, z czytelną / przydatną datą wyjściową
Jake N
najbardziej niezawodny (i bardzo prosty), ponieważ przyznany czas jest sekwencyjny numerycznie (dlatego zawsze odpowiednio sortowalny), dzięki!
Aquarius Power
1
Mam ten alias do wyszukiwania najnowszych plików w moim ~/.zshrc: fr () { find ./ -iname "*"$@"*" -printf "%T@ %Td-%Tb-%TY %Tk:%TM %p\n" | sort -n | cut -d " " -f 2- | grep -i "$@" ; }Rekurencyjnie wyszukuje wszystkie pliki zawierające wzorzec pierwszego argumentu przekazanego do polecenia ( fr <pattern>) i sortuje je według ostatniego.
joelostblom
To jest świetne !!! Aby używać z dowiązaniami symbolicznymi, użyjfind -L ...
Varun Chandak
1
Możesz użyć, ssedaby pozbyć się części ułamkowej sekundy, a następnie użyć ISO8601, ponieważ @PeterMortensen pokazał:find . -type f -printf "%TY-%Tm-%TdT%TT %p\n" | sort -r | ssed -R 's/^([^.]+)\.\d+ (.*)$/\1 \2/'
Ludovic Kuty
83

Najłatwiejszą metodą jest użycie zsh, dzięki jego kwalifikatorom glob .

print -lr -- $dir/**/$str*(om[1,10])

Jeśli masz GNU find, pozwól mu wydrukować czasy modyfikacji pliku i posortuj według tego.

find -type f -printf '%T@ %p\0' |
sort -zk 1nr |
sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10

Jeśli masz GNU find, ale nie inne narzędzia GNU, użyj znaku nowej linii jako separatora zamiast null; utracisz wsparcie dla nazw plików zawierających nowe linie.

find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^ ]* //' | head -n 10

Jeśli masz Perla (tutaj zakładam, że nie ma nowych linii w nazwach plików):

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        @sorted = sort {$_{$a} <=> $_{$b}} keys %_;  # sort by increasing age
        print @sorted[0..9];
    }'

Jeśli masz Python (zakładając również, że w nazwach plików nie ma nowego wiersza):

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in (sorted(times.iterkeys(), key=lambda f:times[f], reverse=True))[:10]: print f'

Prawdopodobnie jest sposób, aby zrobić to samo w PHP, ale nie wiem.

Jeśli chcesz pracować tylko z narzędziami POSIX, jest to bardziej skomplikowane; zobacz Jak rekursywnie wyświetlać listę plików posortowanych według daty modyfikacji (brak dostępnej komendy stat!) (powtórzenie pierwszych 10 jest łatwą częścią).

Gilles
źródło
Myślę, że findwersja pokazuje najstarsze pliki i do tej -ropcji należy dodać opcję sort.
Quentin Pradet
Mój sed mówi, że nie ma opcji -z.
Kef Schecter
@KefSchecter Następnie użyj znaku nowej linii jako separatora, ale utracisz obsługę znaku nowej linii w nazwach plików.
Gilles
Powyższe dotyczy python2. Jeśli masz tylko python3, kilka małych zmian: python3 -c 'import os, sys; times = {} dla f w sys.stdin.readlines (): f = f [0: -1]; times [f] = os.stat (f) .st_mtime for f in (sorted (times.keys (), key = lambda f: times [f], reverse = True)) [: 10]: print (f); „
Neil McGill,
40

Nie potrzebujesz PHP ani Python, po prostu ls :

man ls:
-t     sort by modification time
-r,    reverse order while sorting (--reverse )
-1     list one file per line

find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;

Jeśli polecenie * zakończy się ze statusem niepowodzenia (tj. Lista argumentów jest za długa ), możesz iterować z find. Parafrazując z: Maksymalna długość argumentów dla nowego procesu

  • find . -print0|xargs -0 command (optymalizuje prędkość, jeśli find nie implementuje „-exec +”, ale zna „-print0”)
  • find . -print|xargs command (jeśli w argumentach nie ma białych znaków)

Jeśli główna część argumentów składa się z długich, bezwzględnych lub względnych ścieżek, spróbuj przenieść swoje działania do katalogu: cd /directory/with/long/path; command *innym szybkim rozwiązaniem może być dopasowanie mniejszej liczby argumentów:command [a-e]*; command [f-m]*; ...

Ярослав Рахматуллин
źródło
1
Jeśli jest dużo plików, kończy się to niepowodzeniem z powodu „zbyt długiej listy argumentów” na ls.
occulus
1
To prawda, ale wierzę, że pytanie brzmiało: „jak zrobić proste znalezisko ...”
Ярослав Рахматуллин
2
ls nie cytuje nazw plików w sposób zrozumiały dla xargs (brak opcji -0, a różne style cytowania są nieodpowiednie)
Tobu,
10

Potrzebujesz tylko ls

Możesz zrobić find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;jak podano powyżej,

lub

ls -1rt `find /wherever/your/file/hides -type f`
skippy1910
źródło
2
Jeśli jest dużo plików, kończy się to niepowodzeniem z powodu „zbyt długiej listy argumentów” na ls. Może ponownie używałeś xargs?
occulus
2
Ale jeśli xargspołączenia będą wykonywane lswiele razy, sortowanie zostanie przerwane.
Aaron D. Marasco,
Nie udaje się to w przypadku plików ze spacjami w nazwach. Jakakolwiek rada?
user74094,
Natknąłem się na tę odpowiedź i dokładnie tego potrzebowałem w podobnej sytuacji. Pytanie: co robi +;na końcu? Wydaje się dawać ten sam wynik bez, ;jednak nie działa bez +?
RocketNuts
Jest to dokładnie to samo, co inna odpowiedź opublikowana 8 miesięcy wcześniej, z wyjątkiem części o używaniu „ls -1rt` find… `”, która jest zepsuta
Clément
7

Rozszerzanie odpowiedzi użytkownika 195696 :

find . -type f -printf "%T@\t%Tc %6k KiB %p\n" | sort -n | cut -f 2-

Dla każdego pliku, ten pierwszy znacznik czasu wyjścia numeryczne (dla sortowania poprzez, po zestawianiu \t), a następnie czytelne dla znaczników czasu, wówczas rozmiar pliku (niestety findjest -printfnie można zrobić w mebibytes tylko kibibytes), to nazwa pliku ze względną ścieżka.

Następnie sort -nsortuje je według pierwszego pola numerycznego.

Następnie cutusuwa pierwsze pole numeryczne, które nie jest interesujące dla użytkownika. (Drukuje drugie pole dalej). Domyślnym separatorem pól jest \ttabulacja.

Przykład wyniku:

Thu 06 Feb 2014 04:49:14 PM EST     64 KiB ./057_h2_f7_10/h2_f7_10.class
Fri 07 Feb 2014 02:08:30 AM EST 7962976 KiB ./056_h2_f7_400/h2__rh_4e-4.mph
Fri 07 Feb 2014 02:23:24 AM EST 7962976 KiB ./056_h2_f7_400/h2_f7_400_out_Model.mph
Fri 07 Feb 2014 02:23:24 AM EST      0 KiB ./056_h2_f7_400/h2_f7_400_out.mph.status
Fri 07 Feb 2014 02:23:24 AM EST     64 KiB ./056_h2_f7_400/1579678.out
Fri 07 Feb 2014 03:47:31 AM EST 8132224 KiB ./057_h2_f7_10/h2__rh_1e-5.mph
Fri 07 Feb 2014 04:00:49 AM EST 8132224 KiB ./057_h2_f7_10/h2_f7_10_out_Model.mph
Fri 07 Feb 2014 04:00:49 AM EST      0 KiB ./057_h2_f7_10/h2_f7_10_out.mph.status
Fri 07 Feb 2014 04:00:49 AM EST     64 KiB ./057_h2_f7_10/1579679.out
Fri 07 Feb 2014 09:47:18 AM EST   9280 KiB ./056_h2_f7_400/h2__rh_4e-4.mat
Fri 07 Feb 2014 10:51:23 AM EST   9728 KiB ./018_bidomain/h2_plain__rh_1e-5.mat
Fri 07 Feb 2014 10:58:33 AM EST   9568 KiB ./057_h2_f7_10/h2__rh_1e-5.mat
Fri 07 Feb 2014 05:05:38 PM EST     64 KiB ./058_h2_f7_stationary/h2_f7_stationary.java
Fri 07 Feb 2014 06:06:29 PM EST     32 KiB ./058_h2_f7_stationary/slurm.slurm
Sat 08 Feb 2014 03:42:07 AM EST      0 KiB ./058_h2_f7_stationary/1581061.err
Sat 08 Feb 2014 03:42:14 AM EST     64 KiB ./058_h2_f7_stationary/h2_f7_stationary.class
Sat 08 Feb 2014 03:58:28 AM EST  70016 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mph
Sat 08 Feb 2014 04:12:40 AM EST  70304 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mph
Sat 08 Feb 2014 04:12:53 AM EST  70304 KiB ./058_h2_f7_stationary/h2_f7_stationary_out_Model.mph
Sat 08 Feb 2014 04:12:53 AM EST      0 KiB ./058_h2_f7_stationary/h2_f7_stationary_out.mph.status
Sat 08 Feb 2014 04:12:53 AM EST     32 KiB ./058_h2_f7_stationary/1581061.out
Mon 10 Feb 2014 11:40:54 AM EST    224 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mat
Mon 10 Feb 2014 11:42:32 AM EST    224 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mat
Mon 10 Feb 2014 11:50:08 AM EST     32 KiB ./plot_grid.m

Celowo utworzyłem pole rozmiaru pliku 6 znaków, ponieważ jeśli będzie ono dłuższe, trudno będzie wizualnie rozróżnić, jak duże są pliki. W ten sposób pliki większe niż 1e6 KiB wystają: 1 znak oznacza 1-9 GB, 2 znaki oznacza 10-99 GB itp.


Edycja: oto kolejna wersja (od find . -printf "%Tc"awarii na MinGW / MSYS):

find . -type f -printf "%T@\t%p\n" | sort -n | cut -f 2- | xargs -I{} ls -Glath --si {}

Dając wyniki takie jak:

-rw-r--r-- 1 es 23K Jul 10  2010 ./laptop_0000071.jpg
-rw-r--r-- 1 es 43M Jul 29 19:19 ./work.xcf
-rw-r--r-- 1 es 87K Jul 29 20:11 ./patent_lamps/US Patent 274427 Maxim Lamp Holder.jpg
-rw-r--r-- 1 es 151K Jul 29 20:12 ./patent_lamps/Edison screw-in socket.png
-rw-r--r-- 1 es 50K Jul 29 20:13 ./patent_lamps/1157 Lamp.jpg
-rw-r--r-- 1 es 38K Jul 29 20:14 ./patent_lamps/US06919684-20050719-D00001.png

Gdzie:

  • -I{}powoduje, że wystąpienie {}zostaje zastąpione argumentem, a znaki nowej linii są teraz separatorami argumentów (zwróć uwagę na spacje w nazwach plików powyżej).

  • ls -G pomija drukowanie nazwy grupy (marnowanie miejsca).

  • ls -h --sitworzy czytelne dla człowieka rozmiary plików (bardziej poprawne z --si).

  • ls -t sortuje według czasu, co tutaj nie ma znaczenia, ale zwykle tego używam.

Jewgienij Siergiejew
źródło
1
Uwaga: aby posortować według pliku wielkości zamiast, po prostu zastąpić T@By sw każdym z powyższych poleceń.
Evgeni Sergeev
3

Wariant OS X odpowiedzi @ user195696:

  1. Ze znacznikiem czasu:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r
    
  2. Bez znacznika czasu:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r | awk -F' ' '{ print substr($0, length($1) + 2) }'
    
użytkownik9399
źródło
2

Przekonałem się, że wykonuje to zadanie w systemie Mac OS X (i na tyle ogólne, że działa również na innych systemach Unixen):

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort
Bryan Petty
źródło
2
Niestety drukuje to zlokalizowane nazwy miesięcy w mojej konfiguracji w Chorwacji, co powoduje niepoprawne sortowanie.
Ivan Vučica,
Odpowiedź użytkownika195696 działa dla konfiguracji chorwackiej (i innych).
Peter Mortensen,
1

Jeśli twój findwybór jest bardzo prosty, możesz się bez niego obejść i po prostu użyć ls:

ls -1 *.cc # -r -t optional
djc
źródło
1

Próbować:

find '$dir' -name '$str'\* -print | xargs ls -tl | head -10

Ale przydatne jest również filtrowanie danych według -mmin/ -mtimei -type.

Peter Mortensen
źródło
1

Posługiwać się:

find . -type f -mtime 0 -printf "[%TD %TI:%TM%Tp] %s %p\n" | sort -n | awk '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';

To polecenie posortuje pliki według zmodyfikowanej daty.

I wyświetlają się jak:

[12/05/13 03:10PM] 1.75 MB ./file.text
[12/06/13 11:52PM] 2.90 MB ./file2.mp4
[12/07/13 04:11PM] 4.88 MB ./file3.mp4
[12/07/13 09:17PM] 4.74 MB ./test.apk
Akash
źródło
Poprawiłem ten sript obsłużyć spacje w nazwach plików, zobacz superuser.com/a/777007/134532
Jan
1

Mam proste rozwiązanie, które działa zarówno dla FreeBSD (OS X), jak i Linux:

find . -type f -exec ls -t {} +
Alex Shchur
źródło
Działa to doskonale - powinna być poprawna odpowiedź lub przynajmniej wyższa ocena!
digitaltoast
0

Nie sądzę, żeby findmiał jakieś opcje modyfikowania kolejności wyjściowej. -mtimei -mminpozwoli ci ograniczyć wyniki do plików, które zostały zmodyfikowane w określonym przedziale czasu, ale dane wyjściowe nie zostaną posortowane - musisz to zrobić sam. GNU findma -printfopcję, która między innymi pozwoli ci wydrukować czas modyfikacji każdego znalezionego pliku (ciągi formatujące %tlub %Tk); które mogą pomóc ci uporządkować dane findwyjściowe tak, jak chcesz.

Jim Lewis
źródło
0

Poprawiłem odpowiedź Akashs, poprawiając obsługę skryptu w nazwach plików poprawnie:

find . -type f -mtime 0 -printf ";[%TD %TI:%TM%Tp];%s;%p\n" | sort -n | awk -F ";" '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';
Jan
źródło
0

Jeśli chcesz zamówić wszystkie pliki PNG według czasu w $PWD:

Ta prosta-liner daje wszystkim elastyczność regexp na findi na ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
John Smith
źródło
0

Możesz używać statna BSD i Linux (nie na POSIX) w następujący sposób:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | cut -f2-

Jeśli chcesz ograniczyć liczbę:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | head -[the number] | cut -f2-
drawk
źródło
0

Istnieje czysty i solidny sposób na sort | headdatowanie:

Używanie ls -ldo ładnego wydruku

find . ! -type d -printf "%T@ %p\0" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.]\+ //' |
    xargs -0 ls -lt

Jako funkcja :

findByDate() {
    local humansize=''
    [ "$1" = "-h" ] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p\0" |
        sort -zrn |
        head -zn ${1:--0} |
        sed -z 's/^[0-9.]\+ //' |
        xargs -0 ls -dlt${humansize}
}

Może to być uruchamiane z jednym lub dwoma argumentami, a nawet bez:

Usage: findByDate [-h] [lines] [find options]

Próba:

findByDate

Wyświetla listę wszystkich katalogów nie posortowanych według daty. Nota:

Nawet na dużym drzewie systemów plików, jak xargs już otrzymano posortowaną listę, kolejność plików pozostaje poprawna, nawet jeśli lstrzeba ją uruchamiać wiele razy.

findByDate -h 12

Wymienione zostanie jeszcze 12 ostatnich nie katalogów posortowanych według daty, z rozmiarem wydrukowanym w formie czytelnej dla człowieka

findByDate 42 '-type l'

Wymienię 42 ostatnie ostatnie dowiązania symboliczne

findByDate -0 '( -type l -o -type b -o -type s -o -type c )'

Wyświetla listę wszystkich dowiązań symbolicznych, urządzeń blokujących, gniazd i znaków, posortowanych według daty.

Odwracanie kolejności

Wymiana headprzez taili zmienić przełącznik sorti ls:

findByDate() {
    local humansize=''
    [ "$1" = "-h" ] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p\0" |
        sort -zn |
        tail -zn ${1:-+0} |
        sed -z 's/^[0-9.]\+ //' |
        xargs -0 ls -dltr${humansize}
}

Ta sama funkcja, to samo użycie:

Usage: findByDate [-h] [lines] [find options]
F. Hauri
źródło
-1

Jeśli chcesz uzyskać pełną ścieżkę do każdego elementu, możesz zapisać w ten sposób.

 find FIND_ROOT -maxdepth 1 -type f -printf "%T@ %p\n" | sort -nr | head -10 | cut -d ' ' -f 2

Gdzie
-printf "% T @% p \ n" dla podania kryteriów sortowania (data),
'sort -nr' dla sortowania według daty,
nagłówek -10 dla listy 10 najlepszych wyników,
cięcie -d '' -f 2 dla wycięcia wiodący znacznik czasu na każdej linii.

David Jung
źródło
cut -d ' ' -f 2pęknie, jeśli nazwy plików zawierają spacje.
F. Hauri
-3

Mam proste rozwiązanie.

Po przejściu cddo katalogu użyj

find . -iname "*" -ls

śpiewać
źródło
1
To nie sortuje według daty modyfikacji.
DavidPostill