Найдите последний файл по дате изменения

Если я хочу найти последний файл (mtime) в (большом) каталоге, содержащем подкаталоги, как бы я это сделал?

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

С другой стороны, вы могли бы

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

что, безусловно, сработает для такого количества файлов, которое может быть указано одной командой, т.Е. Если у вас есть большой каталог, -exec...\+ будет выдавать отдельные команды; поэтому каждая группа будет отсортирована по ls внутри себя, но не по всему набору; таким образом, головка будет выбирать самую последнюю запись из первой партии.

Есть какие-нибудь ответы?

Вам не нужно повторно обращаться к внешним командам (как ls) потому что find можете сделать все, что вам нужно, с помощью -printf действие:

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

Сегодня у меня была похожая проблема, но я атаковал ее без find. Мне нужно было что-нибудь короткое, по чему я мог бы пробежаться ssh чтобы вернуть последний отредактированный файл в моем домашнем каталоге. Это примерно то, что я придумал:

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

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

Это гораздо менее подробно, чем использование find если все, что вы хотите вернуть, - это имя файла.

Это происходит в моей системе быстрее, чем printf, хотя я не понимаю, почему

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

РЕДАКТИРОВАТЬ: Я предполагаю, что этот пост не является "не особенно полезным", как я думал. Это действительно быстрое решение, которое просто отслеживает самый последний измененный файл (вместо сортировки всего списка файлов).:

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

Конец РЕДАКТИРОВАНИЯ


Не особенно полезный пост, но поскольку в "аранжировке" обсуждалась скорость, я подумал, что поделюсь этим.

Решения arrange и enzotib включают в себя перечисление всех файлов внутри каталога с указанием их mtimes, а затем сортировку. Как вы знаете, сортировка не является необходимой для поиска максимума. Нахождение максимума может быть выполнено за линейное время, но сортировка занимает n log(n) времени [Я знаю, что разница невелика, но все же ;)]. Я не могу придумать аккуратного способа реализации этого. [ПРАВКА: аккуратная (хотя и грязная на вид) и быстрая реализация, представленная выше.]

Следующая лучшая вещь - чтобы найти последний отредактированный файл в каталоге, рекурсивно найдите последний отредактированный файл в каждом подкаталоге уровня 1. Пусть этот файл представляет подкаталог. Теперь отсортируйте файлы уровня 1 вместе с представителями подкаталогов уровня 1. Если количество файлов и вложенных папок уровня 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 find выполняется в другой оболочке. Я попытался определить 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 на моем ПУТИ, а затем запускаю его.

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

#!/bin/bashecho "$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 секунд на моем домашнем заполнителе - решения arrange и enzotib заняли 1,69 и 1,95 секунды соответственно!

Вот вам и превосходство O(n) над O(n log (n))! Будь ты проклят, накладные расходы на вызов функций! [Или, скорее, накладные расходы на вызов скрипта]

Но этот скрипт масштабируется лучше, чем предыдущие решения, и я уверен, что он будет работать быстрее, чем они, в банке памяти Google ; D

Воспользуйся 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];}'

Вы получаете имя файла с наибольшей эпохой == последний измененный файл.

Это далеко не так модно, но этого также можно добиться с помощью Полуночный командир: поиск *, отображение результата на панели, сортировка по времени изменения в обратном порядке.

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

  • Я бы, вероятно, потратил больше времени, чем разница в 9 минут, на то, чтобы придумать правильный вызов поиска :)

  • меньше шансов на ошибку (забыли указать -r для сортировки и т.д. - начните сначала)

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

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

кстати, вам не нужна ни одна из всех этих обратных косых черт.

@enzotib: вы делаете (+), в противном случае вы получите `find: отсутствует аргумент для '-exec"

@arrange: У меня нет этой ошибки, так как + не имеет никакого значения для bash, поэтому нет необходимости избегать его.

@enzotib: ты прав, моя ошибка, извини