Jak rekursywnie wyświetlać listę plików posortowanych według daty modyfikacji (brak dostępnej komendy stat!)

31

Jak mogę uzyskać listę wszystkich plików w bieżącym katalogu wraz z datą ich modyfikacji i posortować według tej daty?

Teraz wiem, jak to osiągnąć z find, stata sort, ale z jakiegoś powodu dziwne statnie jest zainstalowany na tym polu i jest mało prawdopodobne, że mogę go zainstalować.

Jakaś inna opcja?

PS: też gccnie jest zainstalowany

alex
źródło
Czy możesz załadować skompilowany plik binarny i uruchomić go tam?
imz - Ivan Zakharyaschev
@imz: tak, to inna droga. find -printfDziałanie wydaje się być najprostszym chociaż.
Alex

Odpowiedzi:

27

Moja najkrótsza metoda używa zsh:

print -rl -- **/*(.Om)

(dodaj Dkwalifikatory glob, jeśli chcesz również wyświetlić listę ukrytych plików lub plików w ukrytych katalogach).

Jeśli masz GNU find, pozwól mu wydrukować czasy modyfikacji pliku i posortuj według tego. Zakładam, że w nazwach plików nie ma nowych linii.

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

Jeśli masz Perla (ponownie, zakładając, że w nazwach plików nie ma nowych wierszy):

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

Jeśli masz Python (ponownie, zakładając, że nie ma nowych linii w nazwach plików):

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]): print f'

Jeśli masz dostęp SSH do tego serwera, zamontuj katalog przez sshfs na lepiej wyposażonym komputerze:

mkdir mnt
sshfs server:/path/to/directory mnt
zsh -c 'cd mnt && print -rl **/*(.Om)'
fusermount -u mnt

Dzięki tylko narzędziom POSIX jest to o wiele bardziej skomplikowane, ponieważ nie ma dobrego sposobu na znalezienie czasu modyfikacji pliku. Jedynym standardowym sposobem pobierania czasów pliku jest ls, a format wyjściowy jest zależny od ustawień regionalnych i trudny do przeanalizowania.

Jeśli możesz pisać do plików i dbasz tylko o zwykłe pliki, a w nazwach plików nie ma nowych wierszy, oto okropna kludge: twórz twarde linki do wszystkich plików w jednym katalogu i sortuj je według czasu modyfikacji.

set -ef                       # disable globbing
IFS='
'                             # split $(foo) only at newlines
set -- $(find . -type f)      # set positional arguments to the file names
mkdir links.tmp
cd links.tmp
i=0 list=
for f; do                     # hard link the files to links.tmp/0, links.tmp/1, …
  ln "../$f" $i
  i=$(($i+1))
done
set +f
for f in $(ls -t [0-9]*); do  # for each file, in reverse mtime order:
  eval 'list="${'$i'}         # prepend the file name to $list
$list"'
done
printf %s "$list"             # print the output
rm -f [0-9]*                  # clean up
cd ..
rmdir links.tmp
Gilles „SO- przestań być zły”
źródło
Prawdopodobnie najłatwiejszy sposób find . -print | xargs -n99999 -s999999 ls -ltr. Ale ma to problem polegający na tym, że (1) xargsmoże nie pozwolić na -mwięcej niż 512 lub -swięcej niż 5120, i (b) nawet jeśli można to obejść, wciąż istnieje narzucony przez jądro maksymalny rozmiar połączonej listy argumentów i środowiska. Większość twoich pomysłów (oprócz Perla i Pythona) ma ten sam problem, dlatego właśnie unikałem tworzenia długich linii poleceń.
geekozaur
W szczególności regularnie dostaję błędy „zbyt długiej listy argumentów” przy użyciu zshrekurencyjnych globów w ogólnym przypadku.
geekozaur
@geekosaur: Tylko ostatni okropny kludge ma problem z długimi liniami poleceń. W Zsh możesz wiele zrobić dzięki wbudowanym funkcjom (np. print -rl **/*Jedynym ograniczeniem jest ilość wolnej pamięci), a poza tym jest zargs. Twoja propozycja find … | xargs … lsposortuje się poprawnie, jeśli xargszakończy się wywołaniem lstylko raz i nie będzie działać, jeśli w nazwach plików znajdują się znaki specjalne.
Gilles „SO- przestań być zły”
wielkie dzięki za bardzo szczegółową odpowiedź z wieloma opcjami! :)
alex
I dlatego kocham zsh.
Profpatsch,
14

Zakładając GNU find:

find . -printf '%T@ %c %p\n' | sort -k 1n,1 -k 7 | cut -d' ' -f2-

Zmień 1n,1na, 1nr,1jeśli chcesz, aby pliki były wymienione jako najnowsze jako pierwsze.

Jeśli nie masz GNU find, staje się to trudniejsze, ponieważ lsformat znacznika czasu różni się bardzo (na przykład ostatnio zmodyfikowane pliki mają inny styl znacznika czasu).

geekozaur
źródło
W rzeczywistości możesz także zmienić format daty i godziny za pomocą ls --time-style="..."- nie jestem pewien, czy jest to standard, czy GNU, prawdopodobnie GNU.
asoundmove
Zdecydowanie GNU.
geekozaur
@asoundmove: niestety, pudełko jest za stare (RedHat 7.2) i lsnie ma tej opcji.
alex
7

Na Macu nie ma argumentu -printf do znalezienia, ale możesz to zrobić w zamian:

find . -print0 | xargs -0 -n 100 stat -f"%m %Sm %N" | sort -n|awk '{$1="";print}'

killdash9
źródło
0

można tego spróbować (choć trzeba to sam zbudować) https://github.com/shadkam/recentmost

użytkownik3392225
źródło
6
Witamy w wymianie stosów Unix i Linux! Chociaż teoretycznie może to odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj istotne części odpowiedzi i podać odnośnik.
slm
0

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

Dobrze radzi sobie ze spacjami w nazwach plików - nie żebyś ich używał!

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

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 findobfitości można znaleźć, klikając link.

Serge Stroobandt
źródło
0

Mówiąc ogólnie o znalezieniu plików według daty (to nie zadziała w przypadku oryginalnego plakatu, ale skończyłem tutaj, więc pomyślałem, że inni też mogą). W moim przypadku użytkowania chcę wyświetlić listę plików w celu przejrzenia ich przed usunięciem.

W findutils 4.6.0 lubię:

find . -type f -mtime +270 -exec ls -laFGht --time-style=iso {} \+

Powyższe polecenie wyszukuje pliki ( -type f) w bieżącym katalogu roboczym ( .), które zostały zmodyfikowane ponad 270 dni temu ( -mtime +270również -mtime 0będzie produkować ostatnich 24 godzin, a -mtime -5ukazuje ostatnie 5 dni). Następnie używa ich lsdo wyświetlenia według daty, najpierw najnowszej ( -exec ls -laFGht --time-style=iso {} \+)

Oto próbka danych wyjściowych:

-rwxrwx---+ 1 user1 208M 2018-07-16  ./filename.bak*
-rwxrwx---+ 1 user1  702 2018-07-15  ./filename.ldf*
-rwxrwx---+ 1 user1 208M 2018-07-15  ./filename.bak*

Wspaniałą rzeczą jest to, że po przejrzeniu listy łatwo jest zastąpić część listy findpoleceniem delete:

find . -type f -mtime +270 -delete
Steph
źródło