Як перераховувати файли, відсортовані за датою модифікації, рекурсивно (команда stat не доступна!)


31

Як я можу отримати список усіх файлів у поточному каталозі разом з датою їх зміни та відсортованим за цією датою?

Тепер я знаю, як цього досягти за допомогою find, statі sort, але з якихось дивних причин, statце не встановлено на коробці, і навряд чи я можу це встановити.

Будь-який інший варіант?

PS: gccтакож не встановлено


Чи можете ви завантажити компільований двійковий файл і запустити його там?
imz - Іван Захарящев

@imz: так, це ще один шлях. Але, find -printfздається, дія є найпростішою.
alex

Відповіді:


27

Мій найкоротший метод використовує zsh:

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

(додайте Dглобальні класифікатори, якщо ви також хочете перерахувати приховані файли або файли у прихованих каталогах).

Якщо ви знайдете GNU, змусьте його надрукувати час модифікації файлу та відсортувати за цим. Я припускаю, що в іменах файлів немає нових рядків.

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

Якщо у вас є Perl (знову ж таки, якщо в іменах файлів немає нових рядків):

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

Якщо у вас є Python (знову ж таки, якщо в іменах файлів немає нових рядків):

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'

Якщо у вас є доступ SSH до цього сервера, встановіть каталог на sshfs на краще обладнаній машині:

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

З лише інструментами POSIX це набагато складніше, оскільки немає хорошого способу знайти час модифікації файлу. Єдиний стандартний спосіб отримати час файлу - це ls, а формат виводу залежить від локальності та важко аналізувати.

Якщо ви можете писати у файли, і вас цікавлять лише звичайні файли, а у іменах файлів немає нових рядків, ось жахливий хитрощі: створіть жорсткі посилання на всі файли в одному каталозі та сортуйте їх за часом модифікації.

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

Найпростіший спосіб - це, мабуть find . -print | xargs -n99999 -s999999 ls -ltr. Але в цьому є проблема, що (1) xargsможе не дозволити -mбільше 512 або -sбільше 5120, і (b), навіть якщо ви зможете обійти це, все ще існує максимальний розмір ядра комбінованого списку аргументів і середовища. Більшість ваших ідей (окрім Perl та Python) мають ту ж проблему, саме тому я спеціально уникав створення довгих командних рядків.
geekosaur

Зокрема, я регулярно отримую помилки "занадто довгий список аргументів", використовуючи zshрекурсивні глобуси в загальному випадку.
geekosaur

@geekosaur: Тільки в останньому жахливому хижі є проблема з довгими командними рядками. У zsh ви можете зробити багато з вбудованими модулями (наприклад print -rl **/*, єдиний ліміт - скільки вільної пам'яті у вас є), і крім того, що є zargs. Ваша пропозиція find … | xargs … lsбуде сортована правильно, якщо в xargsкінцевому підсумку викликається lsлише один раз, і не буде працювати, якщо в іменах файлів є спеціальні символи.
Жил "ТАК - перестань бути злим"

велике спасибі за надзвичайно детальну відповідь з безліччю варіантів! :)
alex

І тому я люблю zsh.
Profpatsch

14

Припустимо, GNU find:

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

Змініть 1n,1на, 1nr,1якщо ви хочете, щоб перші файли були перелічені останні.

Якщо у вас немає GNU, findце стає складніше, тому щоls формат часової мітки настільки різниться (наприклад, нещодавно змінені файли мають інший стиль часової мітки).


Насправді ви також можете змінити формат дати та часу ls --time-style="..."- я не впевнений, чи це стандартний стандарт, чи GNU, швидше за все, GNU.
asoundmove

Однозначно GNU.
geekosaur

@asoundmove: на жаль, поле занадто старе (RedHat 7.2) і lsне має такої можливості.
алекс

7

На mac немає аргументу -printf для пошуку, але ви можете зробити це замість цього:

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



0

Ігнорування прихованих файлів - з приємним та швидким штампом часу

Добре обробляє пробіли у назви файлів - це не те, що вам слід використовувати!

$ 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

Більше findбагатства можна знайти за посиланням.


0

Якщо говорити про пошук файлів за датою (це не спрацює за оригінальним плакатом, але я закінчився тут, тому я подумав, що і інші). У моєму випадку використання я хочу перерахувати файли з метою перегляду їх перед видаленням.

З findutils 4.6.0 мені подобається:

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

Вищевказана команда знаходить файли ( -type f) у поточному робочому каталозі ( .), які були змінені більше 270 днів тому ( -mtime +270Також -mtime 0буде видано останні 24 години та -mtime -5відображаються останні 5 днів). Потім він використовуєls для їх переліку за датою, найновіше спочатку ( -exec ls -laFGht --time-style=iso {} \+)

Ось зразок результату:

-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*

Чудова річ у тому, що після перегляду списку його просто замінити частину списку findкомандою delete:

find . -type f -mtime +270 -delete
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.