Знайдіть останній файл за модифікованою датою


39

Якщо я хочу знайти останній файл (mtime) у (великому) каталозі, що містить підкаталоги, як би це зробити?

Багато знайдених мною публікацій пропонують певну різницю ls -lt | head(кумедно, багато хто вважає, ls -ltr | tailщо це однаково, але менш ефективно), що добре, якщо у вас немає підкаталогів (я це роблю).

Потім знову можна

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

який неодмінно зробить трюк для стількох файлів, скільки можна вказати однією командою, тобто, якщо у вас є великий каталог, -exec...\+випустіть окремі команди; тому кожна група буде сортована в lsмежах себе, але не за загальним набором; Тому голова підбере найсвіжіший запис першої партії.

Будь-які відповіді?


btw, вам не потрібна жодна з усіх цих зворотних нахилів.
enzotib

@enzotib: ти робиш ( \ + ), інакше отримаєшfind: missing argument to '-exec'
влаштуй

@arrange: У мене немає цієї помилки, оскільки +вона не має жодного значення bash, тому не потрібно уникати її.
enzotib

@enzotib: ти маєш рацію, моя помилка, вибач
влаштуй

Відповіді:


46

Вам не потрібно повторюватись із зовнішніми командами (як ls), тому що ви findможете виконати все необхідне за допомогою -printfдії:

find /path -printf '%T+ %p\n' | sort -r | head

1
Так, я придумав, find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1але ваше рішення набагато чистіше!
Багатий

3
Додайте, | cut -d ' ' -f2щоб отримати лише ім'я файлу
qwr

Ви також можете зменшити результат, headщоб включити певну кількість рядків. Мені потрібен був лише перший рядок, тому я використавhead -n 1
Timmah

8

У мене була подібна проблема сьогодні, але я напав на неї без find. Мені потрібно було щось коротке, що я міг би перебігтиssh щоб повернути останній редагований файл у моєму домашньому каталозі. Це приблизно те, що я придумав:

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

-pваріантls додає слеш в каталогах, то grep -vвидаляє рядки , що закінчуються на слеш (ака, все каталоги), і head -1обмежує вихід в один файл.

Це набагато менше багатослівного, ніж використання, findякщо все, що ви хочете повернути, це ім'я файлу.


Це не обробляє підкаталоги.
Клімент

4

Це в моїй системі швидше printf, хоча я не розумію, чому

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head

Я підтверджую, швидше.
enzotib

Ще один момент, ... | sort -r | head -n1 | cut -d " " -f 4-якщо ви хочете отримати лише ім'я файлу.
林果 皞

Я просто виявив, що sort -rбуде неправильним, якщо існує ім'я файлу в декількох рядках.
林果 皞

2

EDIT: Я думаю, цей пост не є «особливо корисним», як я вважав, що це було. Це дійсно швидке рішення, яке просто відстежує останній змінений файл (замість сортування всього списку файлів):

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

Для ясності розведіть по декількох рядках, це виглядає наступним чином:

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

Кінець EDIT


Не особливо корисна публікація, але оскільки "домовитись" обговорювали швидкість, я подумав, що поділюсь цим.

Рішення домовленостей та enzotib передбачають перерахування всіх файлів всередині каталогу з їх часом, а потім сортування. Як відомо, сортування не потрібно, щоб знайти максимум. Знайти максимум можна за лінійним часом, але сортування займає n log (n) часу [я знаю, різниця не велика, але все ж;)]. Я не можу придумати акуратний спосіб здійснення цього. [EDIT: акуратний (хоч і брудний вигляд) та швидке впровадження передбачено вище.]

Наступне найкраще - Щоб знайти останній редагований файл у каталозі, рекурсивно знайдіть останній редагований файл у кожному підкаталозі першого рівня. Нехай цей файл представляє підкаталог. Тепер сортуйте файли першого рівня разом із представниками підкаталогій рівня 1. Якщо кількість файлів першого рівня та підкаталоги кожного каталогу майже постійні, то цей процес повинен масштабуватися лінійно із загальною кількістю файлів.

Ось що я придумав, щоб реалізувати це:

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 .

Я запустив це і отримав купу find: findrecent: No such file or directoryпомилок. Причина: -exec знаходження запуску в іншій оболонці. Я спробував визначити findrecent у .bashrc, .xsessionrc, але це не допомогло [я вдячний допомозі тут]. Врешті-решт я вдався поставити

#!/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;

в сценарії, який називається findrecentв моєму PATH, а потім його запуску.

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

#!/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;

і спробував ще раз. Це спрацювало - але на мою домашню папку пішло 1 хвилину 35 секунд - рішення аранжування та рішення Enzotib зайняли відповідно 1,69, 1,95 секунди!

Стільки за перевагу O (n) над O (n log (n))! Чорт ти функціонує накладні! [Точніше, накладні виклики сценарію]

Але цей сценарій масштабується краще, ніж попередні рішення, і я думаю, що він буде працювати швидше, ніж вони в банку пам'яті google; D


2

Використання perlв кон'юнктині з find:

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

Ви отримуєте ім'я файлу з найбільшою зміненою epoch == останнього файлу.


1

Це не так модно, але це також можливо досягти за допомогою командира Midnight Commander : пошук *, панелізація результату, сортування за часом модифікації у зворотному порядку.

Очевидно, це трохи повільніше, ніж find- мій домашній каталог, що містить 922000 файлів, був відсортований mcмайже за 14 хвилин, findвитративши менше 5 - але є деякі переваги:

  • Я, мабуть, витратив би більше часу, ніж 9 хвилин різниці, придумуючи належну виклик пошуку :)

  • менший шанс помилки (забув вказати -r для сортування тощо - запустити знову)

  • можна грати з набором результатів, змінюючи порядок сортування тощо - без повторного запиту файлів.

  • можна виконати операції з файлами лише на деяких файлах із набору результатів - тобто сортувати за розміром, видалити кілька великих файлів, які не потрібні

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