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

  • Операционная система: Linux

  • Тип файловой системы: ext3

  • Предпочтительное решение: bash (script/oneliner), ruby, python

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

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

./alfa/beta/gamma/example.txt

и я изменяю содержимое файла example.txt, мне нужно, чтобы это время отображалось рядом с каталогом первого уровня alfa в читаемой человеком форме, а не в эпоху. Я пробовал некоторые вещи, используя find, xargs, sort и подобные, но я не могу обойти проблему, что временная метка файловой системы 'alfa' не изменяется, когда я создаю/изменяю файлы на несколько уровней вниз.

Ответ 1

Попробуйте следующее:

#!/bin/bash
find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

Выполните его с помощью пути к каталогу, где он должен начать сканирование рекурсивно (он поддерживает имена файлов с пробелами).

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

#!/bin/bash
find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

что немного быстрее.

Ответ 2

Чтобы найти все файлы, статус которых был последним изменен N минут назад:

find -cmin -N

например:

find -cmin -5

Ответ 3

GNU Find (см. man find) имеет параметр -printf для указания файлов EPOC mtime и относительного пути.

redhat> find . -type f -printf '%[email protected] %P\n' | sort -n | awk '{print $2}'

Ответ 4

Я укоротил гало удивительный ответ на этот однострочный

stat --printf="%y %n\n" $(ls -tr $(find * -type f))

Обновлено: если в именах файлов есть пробелы, вы можете использовать эту модификацию

OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS";

Ответ 5

Попробуйте это

#!/bin/bash
stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)

Он использует find для сбора всех файлов из каталога, ls, чтобы их отсортировать по дате изменения, head для выбора 1-го файла и, наконец, stat, чтобы показать время в хорошем формате.

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

Ответ 6

Эта команда работает в Mac OS X:

find "$1" -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

В Linux, как попросил исходный плакат, используйте stat вместо gstat.

Этот ответ, конечно, user37078 выдающееся решение, продвигаемое от комментария к полному ответу. Я смешался с CharlesB, чтобы использовать gstat в Mac OS X. Я получил coreutils из MacPorts, а не homebrew, кстати.

И вот как я упаковал это в простую команду ~/bin/ls-recent.sh для повторного использования:

#!/bin/bash
# ls-recent: list files in a dir tree, most recently modified first
#
# Usage: ls-recent path [-10 | more]
# 
# Where "path" is a path to target directory, "-10" is any arg to pass
# to "head" to limit the number of entries, and "more" is a special arg
# in place of "-10" which calls the pager "more" instead of "head".
if [ "more" = "$2" ]; then
   H=more; N=''
else
   H=head; N=$2
fi

find "$1" -type f -print0 |xargs -0 gstat --format '%Y :%y %n' \
    |sort -nr |cut -d: -f2- |$H $N

Ответ 7

Оба решения perl и Python в этом сообщении помогли мне решить эту проблему в Mac OS X: https://unix.stackexchange.com/questions/9247/how-to-list-files-sorted-by-modification-date-recursively-no-stat-command-avail.

Цитата из сообщения:

Perl:

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

Python:

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in sorted(times.iterkeys(), key=lambda f:times[f]): print f'

Ответ 8

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

Существует два способа сделать это:


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

linux> touch -d @0 /tmp/a;
linux> find . -type f -exec tcsh -f -c test `stat --printf="%X" {}` -gt  `stat --printf="%X" /tmp/a`  ; -exec tcsh -f -c touch -a -r {} /tmp/a ; -print 

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


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

linux> \find . -type f -exec stat --printf="%X  %n\n" {} \; | \sort -n | tail -1

И там у вас есть...

Ответ 9

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

$ alias | grep xlogs
xlogs='sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R'

Таким образом, он делает то, что вы ищете (за исключением того, что он не меняет дату/время нескольких уровней) - ищет в этом случае последние файлы (*.log и *.trc файлы); также он находит файлы, измененные в последний день, затем сортирует по времени и выводит каналы через меньшее:

sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R

пс. Заметьте, что у меня нет root на некоторых серверах, но всегда есть sudo, поэтому вам может не понадобиться эта часть.

Ответ 10

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

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

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

2017.01.28 07h00 Sat ./recent
2017.01.21 10h49 Sat ./hgb
2017.01.16 07h44 Mon ./swx
2017.01.10 18h24 Tue ./update-stations
2017.01.09 10h38 Mon ./stations.json

Подробнее find в изобилии можно найти по ссылке.

Ответ 11

Быстрая функция bash:

# findLatestModifiedFiles(directory, [max=10, [format="%Td %Tb %TY, %TT"]])
function findLatestModifiedFiles() {
    local d="${1:-.}"
    local m="${2:-10}"
    local f="${3:-%Td %Tb %TY, %TT}"

    find "$d" -type f -printf "%[email protected] :$f %p\n" | sort -nr | cut -d: -f2- | head -n"$m"
}

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

findLatestModifiedFiles "/home/jason/" 1

Вы также можете указать свой собственный формат даты/времени в качестве третьего аргумента.

Ответ 12

Ниже приведена строка метки времени и имени файла с самой последней отметкой времени:

find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p\n" | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' |     sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1

Результатом вывода формы: <yy-mm-dd-hh-mm-ss.nanosec> <filename>

Ответ 13

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

find . -type f -printf "%[email protected] %p\0" | sort -zk1nr
  • find ... -printf печатает модификацию файла (значение EPOCH), за которым следует пробел и \0 завершенные имена файлов.
  • sort -zk1nr считывает завершенные NUL данные и сортирует их в обратном порядке

Как вопрос помечен Linux, поэтому я предполагаю, что gnu доступны utils.

Вы можете выполнить следующее:

xargs -0 printf "%s\n"

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

Ответ 14

Вы можете дать команде printf найти попытку

% Текущее время доступа к файлу Ak формат, заданный k,                      который является либо @' or a directive for the C strftime '                      функция. Возможные значения для k перечислены ниже;                      некоторые из них могут быть недоступны на всех систем, должных                      к различиям в `strftime 'между системами.

Ответ 15

Для обычного вывода ls используйте это. Список аргументов отсутствует, поэтому он не может быть слишком длинным:

find . | while read FILE;do ls -d -l "$FILE";done

И смириться с cut только для дат, времени и имени:

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5

EDIT: только что заметил, что текущий верхний ответ сортируется по дате изменения. Это так же просто со вторым примером здесь, так как дата модификации сначала на каждой строке - поместите сортировку в конец:

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 | sort

Ответ 16

Это можно сделать с помощью рекурсивной функции в bash тоже

Пусть F - функция, отображающая время файла, которое должно лексикографически сортироваться yyyy-mm-dd и т.д., (os-depend?)

F(){ stat --format %y "$1";}                # Linux
F(){ ls -E "$1"|awk '{print$6" "$7}';}      # SunOS: maybe this could be done easier

R - рекурсивная функция, проходящая через каталоги

R(){ local f;for f in "$1"/*;do [ -d "$f" ]&&R $f||F "$f";done;}

И наконец

for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done

Ответ 17

Вот что я использую (очень эффективно):

function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P\n' 2>/dev/null | sort | tail -n "${2:-10}" }

ПЛЮСЫ:

  • порождает только 3 процесса

ИСПОЛЬЗОВАНИЕ:

find_last [dir [number]]

где:

  • dir - каталог для поиска [текущий каталог]
  • number - количество новейших файлов для отображения [10]

Вывод для find_last/etc 4 выглядит следующим образом:

2019-07-09 12:12 cups/printers.conf
2019-07-09 14:20 salt/minion.d/_schedule.conf
2019-07-09 14:31 network/interfaces
2019-07-09 14:41 environment