Как рекурсивно найти последний измененный файл в каталоге? - PullRequest
223 голосов
/ 30 декабря 2010

Кажется, что ls неправильно сортирует файлы при выполнении рекурсивного вызова:

ls -altR . | head -n 3

Как найти последний измененный файл в каталоге (включая подкаталоги)?

Ответы [ 19 ]

334 голосов
/ 30 декабря 2010
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

Для огромного дерева sort может быть трудно хранить все в памяти.

%T@ дает вам время модификации как метку времени Unix, sort -n численно сортирует,tail -1 занимает последнюю строку (самая высокая временная метка), cut -f2 -d" " обрезает первое поле (временную метку) из выходных данных.

Edit: Так же, как -printf, вероятно, GNU-только, ajreals использование stat -c тоже.Хотя в BSD можно сделать то же самое, параметры форматирования разные (-f "%m %N", казалось бы)

И я пропустил часть множественного числа;если вам нужно больше, чем последний файл , просто увеличьте аргумент tail.

120 голосов
/ 29 января 2012

После ответа @ plundra , вот версия BSD и OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "
15 голосов
/ 30 декабря 2010

Вместо сортировки результатов и сохранения только последних измененных, вы можете использовать awk для печати только того, который имеет наибольшее время модификации (во времени Unix):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Это должно быть быстреечтобы решить вашу проблему, если количество файлов достаточно велико.

Я использовал символ NUL (то есть '\ 0'), потому что, теоретически, имя файла может содержать любой символ (включая пробел и символ новой строки), но это.

Если в вашей системе нет таких патологических имен файлов, вы также можете использовать символ новой строки:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Кроме того, это работает и в mawk.

10 голосов
/ 05 сентября 2013

Мне не удалось найти последний измененный файл в Solaris 10. Там find не имеет опции printf, а stat недоступен. Я обнаружил следующее решение, которое хорошо работает для меня:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Чтобы показать имя файла, также используйте

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Объяснение

  • find . -type f находит и перечисляет все файлы
  • sed 's/.*/"&"/' заключает путь в кавычки для обработки пробелов
  • xargs ls -E отправляет указанный путь в ls, опция -E гарантирует, что возвращается полная метка времени (формат год-месяц-день час-минуты-секунды-наносекунды )
  • awk '{ print $6," ",$7 }' извлекает только дату и время
  • awk '{ print $6," ",$7," ",$9 }' извлекает дату, время и имя файла
  • sort возвращает файлы, отсортированные по дате
  • tail -1 возвращает только последний измененный файл
9 голосов
/ 29 ноября 2013

Кажется, это работает нормально, даже с подкаталогами:

find . -type f | xargs ls -ltr | tail -n 1

В случае слишком большого количества файлов уточните поиск.

6 голосов
/ 08 октября 2015

Показывает последний файл с удобочитаемой отметкой времени:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Результат выглядит так:

2015-10-06 11:30: +0200 ./foo/bar.txt

Чтобы показать больше файлов, замените -n1 на большее число

4 голосов
/ 30 декабря 2010

Это дает отсортированный список:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Обратный порядок, поместив '-r' в команду сортировкиЕсли вам нужны только имена файлов, вставьте "awk '{print $ 11}' |"до '|голова '

3 голосов
/ 29 октября 2015

Я столкнулся с той же проблемой. Мне нужно найти самый последний файл рекурсивно. поиск занял около 50 минут.

Вот небольшой скрипт, чтобы сделать это быстрее:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

Это рекурсивная функция, которая получает самый последний измененный элемент каталога. Если этот элемент является каталогом, функция вызывается рекурсивно и выполняет поиск в этом каталоге и т. Д.

3 голосов
/ 16 марта 2016

Я все время пользуюсь чем-то похожим, а также списком самых последних измененных файлов.Для больших деревьев каталогов это может быть намного быстрее, чтобы избежать сортировки .В случае только что топ-1 самого последнего измененного файла:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

В каталоге, содержащем 1,7 миллиона файлов, я получаю самый последний в 3,4 с, ускорение в 7,5 раз по сравнению с 25,5решение с использованием сортировки.

3 голосов
/ 14 ноября 2013

В Ubuntu 13 следующее делает это, может быть, чуть быстрее, так как оно меняет сортировку и использует «голову» вместо «хвоста», сокращая работу.Чтобы показать 11 новых файлов в дереве:

найти.-тип f -printf '% T @% p \ n' |сортировать -n -r |голова -11 |cut -f2- -d "" |sed -e 's, ^. / ,,' |xargs ls -U -l

Это дает полный список ls без повторной сортировки и пропускает раздражающий './', который 'find' помещает в каждое имя файла.

Или, как функция bash:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

Тем не менее, большая часть работы была сделана с помощью оригинального решения Plundra.Спасибо, Пундра.

...