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

242

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

ls -altR . | head -n 3

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

JMW
источник

Ответы:

358
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

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

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

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

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

plundra
источник
7
Если порядок имеет значение, вы можете переключить использование sort -rn | head -3вместо sort -n | tail -3. Одна версия предоставляет файлы от самых старых до самых новых, а другая - от самых новых до самых старых.
Дон Фолкнер
3
У меня был огромный каталог (около десяти тысяч небольших файлов), и я беспокоился о производительности, но ... эта команда была выполнена менее чем за одну секунду! Отлично, большое спасибо !!! :-)
lucaferrario
2
«Для огромного дерева, может быть, трудно сортировать все в памяти». sortсоздаст временные файлы (в /tmp) по мере необходимости, поэтому я не думаю, что это проблема.
Владимир Пантелеев
1
изменив его на: -printf '%T@ %Tb %Td %TY %p\n'даст вам штамп даты (при необходимости) (аналогично ls)
bshea
1
Я нахожу следующий более короткий и с более find . -type f -printf '%TF %TT %p\n' | sort | tail -1
понятным
129

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

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "
Эмерсон Фарругия
источник
1
findПоддерживает ли BSD / OS X +вместо \;? Потому что это делает то же самое (передача нескольких файлов в качестве параметров), без -print0 | xargs -0конвейера.
DevSolar
Что делать, если я хочу изменить последние 5 или n файлов в порядке убывания?
Кхуншан
@khunshan изменить head -1кhead -5
Эмерсон Farrugia
20

Вместо того, чтобы сортировать результаты и сохранять только последние измененные, вы можете использовать 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.

марко
источник
Это может быть легко адаптировано, чтобы сохранить три самых последних.
Приостановлено до дальнейшего уведомления.
1
Это не работает mawk, стандартная альтернатива Debian.
Jan
Нет, но в этом случае вы можете использовать символ новой строки, если он вас не беспокоит;)
marco
10

У меня была проблема, чтобы найти последний измененный файл под 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

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

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

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

mgratia
источник
1
-lВариант lsкажется ненужным. Просто -trкажется достаточным.
Acumenus
6
Это похоже на сортировку по каталогу, поэтому не обязательно будет показывать последний файл
Фабиан Шменглер
1
Если в путях к файлам есть пробелы, лучше сделать:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Периодическое обслуживание
Это не находит последние файлы для меня.
К.-Майкл Ай
1
Думайте, что это сломается, если в именах файлов есть пробелы
waferthin
7

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

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

Фабиан Шменглер
источник
5

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

Пьер Д
источник
Очень круто: я только что обменял последний отпечаток на: system ("ls -l $ f"), если eof (), чтобы увидеть дату тоже хорошо.
Мартин Т.
@MartinT. : отлично, и не за что. Мне странно, что у людей есть этот инстинкт сортировки (O (n log n)), когда доступен метод O (n). Это, кажется, единственный ответ, избегающий сортировки. Кстати, цель команды, которую я предложил, - просто найти путь к последнему файлу. Вы можете использовать псевдоним команды в своей оболочке (например, as lastfile), а затем вы можете делать с результатом все, что захотите, например ls -l $(lastfile .), или open $(lastfile .)(на Mac) и т. Д.
Pierre D
О, я исправлен: я вижу другой ответ ниже (@marco). +1.
Пьер Д
4

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

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

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

Karlo
источник
3

В 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. Спасибо, Пундра.

Rickys
источник
3

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

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

AnatomicJC
источник
3

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

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

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

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

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '
snth
источник
2

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

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 
Маттиас Вадман
источник
2

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

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
rwhirn
источник
1
Он плохо работает, если какие-либо директории содержат пробелы - нужно установить IFS и использовать кавычки: IFS = $ '\ n'; для директории в $ (find ./ -type d); do echo "$ dir"; найти тип $ dir f -printf '% T @ "% p" \ n' | сортировать -n | хвост -1 | cut -f2- -d "" | xargs -I {} touch -r {} "$ dir"; сделано;
Энди Ли Робинсон
2

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

ls -1t | head -1

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

Анкит Залани
источник
10
Нет, не будет, так как не является рекурсивным.
arataj
1

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

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l
Роджер Кейбл
источник
1

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

find . -name "*zip" -type f | xargs ls -ltr | tail -1 
RahulM
источник
1

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

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

Серж Строобандт
источник
1

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

$ find /target_directory -type f -mmin -60

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

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r
Акаша
источник
0

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

find . -type f -print0|xargs -0 ls -drt|tail -n 1
user3295940
источник
0

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

https://github.com/bucknerns/logtail

Установка:

pip install logtail

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

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

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

editlatest <log dir> [<glob match: default=*.log>]
Натан Бакнер
источник