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

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

ls -altR . | head -n 3

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

Ответ 1

find . -type f -printf '%[email protected] %p\n' | sort -n | tail -1 | cut -f2- -d" "

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

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

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

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

Ответ 2

Следуя @plundra answer, здесь версия BSD и OS X:

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

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

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 на большее число

Ответ 7

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

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

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

Ответ 8

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

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

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

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

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

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

Ответ 9

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

Вот немного script, чтобы сделать это быстрее:

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

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

Ответ 10

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

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

В каталоге, содержащем 1,7 миллиона файлов, я получаю самую последнюю версию в 3.4s, ускорение 7.5x против решения 25.5s с использованием сортировки.

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

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

ls -1t | head -1

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

Ответ 14

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

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

Ответ 15

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

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

Ответ 16

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

$ 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 изобилии по ссылке.

Ответ 17

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

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

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

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

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

Ответ 18

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

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

Ответ 19

Я написал пакет 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>]

Ответ 20

Для поиска файлов в /target_directory и всех его подкаталогах, которые были изменены за последние 60 минут:

$ find /target_directory -type f -mmin -60

Чтобы найти самые последние измененные файлы, отсортированные в обратном порядке времени обновления (то есть сначала самые последние обновленные файлы):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r