Как рекурсивно находить и перечислять последние измененные файлы в каталоге с подкаталогами и временем?
-
Операционная система: 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