Как рекурсивно найти последний измененный файл в каталоге?

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

ls -altR . | head -n 3

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

19 ответов


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" казалось бы)

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


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

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "

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

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

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

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

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

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

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


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

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

показать имя файла, а также использовать

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

объяснение

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

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

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

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


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

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 С большим номером


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

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

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


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

найти . - введите f-printf '%T@ %p\n' / sort-n-r | head -11 | cut - f2- - d" " | sed-e 's,^./ ,, '/xargs ls-U-l

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

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

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

тем не менее, большая часть работы была выполнена оригинальным решением plundra. Спасибо plundra.


это рекурсивно изменяет время модификации всех каталогов в текущем каталоге на самый новый файл в каждом каталоге:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done

этот простой cli также будет работать:

ls -1t | head -1

вы можете изменить -1 на количество файлов, которые вы хотите перечислить


я столкнулся с той же проблемой. Мне нужно найти самый последний файл рекурсивно. поиск занял около 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

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


Я использую что-то подобное все время, а также список top-k самых последних измененных файлов. Для больших деревьев каталогов это может быть намного быстрее, чтобы избежать сортировки. В случае только top-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 s, ускорение 7,5 x против решения 25,5 s с помощью сортировки.


если работает stat на каждом файле по отдельности, чтобы замедлить вы можете использовать xargs чтобы немного ускорить события:

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 

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

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l

на Solaris работала следующая команда:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 

Я предпочитаю этот, он короче:

find . -type f -print0|xargs -0 ls -drt|tail -n 1

Я написал пакет pypi/github для этого вопроса, потому что мне также нужно было решение.

https://github.com/bucknerns/logtail

установка:

pip install logtail

использование: хвосты изменили файлы

logtail <log dir> [<glob match: default=*.log>]

Usage2: открывает последний измененный файл в Редакторе

editlatest <log dir> [<glob match: default=*.log>]

игнорирование скрытых файлов-с хорошей и быстрой отметкой времени

обрабатывает пробелы в именах файлов хорошо - не то, что вы должны использовать их!

$ 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 Галор можно найти по ссылке.


Я нахожу следующее короче и с более интерпретируемым выходом:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

учитывая фиксированную длину стандартизированного формата ISO datetimes, лексикографическая сортировка прекрасна, и нам не нужна -n опция сортировки.

Если вы хотите удалить метки времени снова, вы можете использовать:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '