How to recursively find and list the latest modified files in a directory with subdirectories and times
I have several directories with several subdirectories and files in them. I need to make a list of all these directories that is constructed in a way such that every first-level directory is listed next to the date and time of the latest created/modified file within it.
To clarify, if I touch a file or modify its contents a few subdirectory levels down, that timestamp should be displayed next to the first-level directory name. Say I have a directory structured like this:
and I modify the contents of the file example.txt , I need that time displayed next to the first-level directory alfa in human readable form, not epoch. I’ve tried some things using find, xargs , sort and the like, but I can’t get around the problem that the filesystem timestamp of ‘alfa’ doesn’t change when I create/modify files a few levels down.
@user3392225 A fork of github / shadkam / recentmost can be found at github.com/ConradHughes/recentmost with the -0 option to use with find ‘s -print0
22 Answers 22
#!/bin/bash find $1 -type f -exec stat --format '%Y :%y %n' "<>" \; | sort -nr | cut -d: -f2- | head
Execute it with the path to the directory where it should start scanning recursively (it supports filenames with spaces).
If there are lots of files it may take a while before it returns anything. Performance can be improved if we use xargs instead:
#!/bin/bash find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head
Your «fast method» should also be able to use print0 to support spaces and even linefeeds in filenames. Here’s what I use: find $1 -type f -print0 | xargs -0 stat —format ‘%Y :%y %n’ | sort -nr | cut -d: -f2- | head This still manages to be fast for me.
Some directories I was looking in didn’t allow me to stat them, so I made the following changes (to the ‘fast’ one) so I didn’t have to see the errors in my final output. find $ <1>-type f | xargs stat —format ‘%Y :%y %n’ 2>/dev/null | sort -nr | cut -d: -f2-1>
On Mac OS X it’s not GNU’s stat so command fails. You have to brew install coreutils and use gstat instead of stat
You don’t need to run stat since find PATH -type f -printf «%T@ %p\n»| sort -nr does the job. It’s also a bit faster that way.
On Mac OS X, without installing gstat or anything else, you can do: find PATH -type f -exec stat -f «%m %N» «<>» \; | sort -nr | head
To find all files whose file status was last changed N minutes ago:
Use -ctime instead of -cmin for days:
On FreeBSD and MacOS: You can also use -ctime n[smhdw] for seconds, minutes, hours, days, and weeks. Days is the default if no unit is provided.
# FreeBSD and MacOS only: find . -ctime -30s find . -ctime -15 find . -ctime -52w
great idea. Consider doing stat . on directory first to get an idea of modification dates you should be looking at
GNU find (see man find ) has a -printf parameter for displaying the files in Epoch mtime and relative path name.
redhat> find . -type f -printf '%T@ %P\n' | sort -n | awk ''
Thanks! This is the only answer that is fast enough to search through my very wide directory structure in a reasonable time. I pass the output through tail to prevent thousands of lines from being printed in the output.
Another comment: the awk ‘
The -printf variant is far quicker than calling a ‘stat’ process each time — it cut hours off my backup job(s). Thanks for making me aware of this. I avoided the awk/sed thing as I’m only concerned about the last update within the tree — so X=$(find /path -type f -printf ‘%T %p\n’ | grep -v something-I-don-tcare-about | sort -nr | head -n 1) and a echo $ worked well for me (give me stuff up to the first space)
All will not works if filename across multiple line. Use touch «lala
stat --printf="%y %n\n" $(ls -tr $(find * -type f))
If there are spaces in filenames, you can use this modification:
OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS";
This will not work if you have a very large number of files. the answers that use xargs solve that limit.
@carlverbiest indeed a large number of files will break slashdottir’s solution. Even xargs-based solutions will be slow then. user2570243’s solution is best for big filesystems.
IFS=$’\n’ isn’t safe in any event when handling filenames: Newlines are valid characters in filenames on UNIX. Only the NUL character is guaranteed not to be present in a path.
#!/bin/bash stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)
It uses find to gather all files from the directory, ls to list them sorted by modification date, head for selecting the first file and finally stat to show the time in a nice format.
At this time it is not safe for files with whitespace or other special characters in their names. Write a commend if it doesn’t meet your needs yet.
halo: I like your answer, it works well and prints out the correct file. I doesn’t help me however since there are too many sublevels in my case. So I get «Argument list too long» for ls. and xargs wouldn’t help in this case either. I’ll try something else.
I solved this using PHP instead. A recursive function that descends through the filesystem tree and stores the time of the most recently modified file.
On MacOS I needed to use stat $(ls -t $(find alfa/ -type f) | head -n 10) . —format would be -f , but there is no %y and I didn’t bother finding a replacement.
Ignoring hidden files — with nice & fast time stamp
Here is how to find and list the latest modified files in a directory with subdirectories. Hidden files are ignored on purpose. Whereas spaces in filenames are handled well — not that you should use those! The time format can be customised.
$ 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
More find galore can be found by following the link.
This command works on Mac OS X:
find «$1» -type f -print0 | xargs -0 gstat —format ‘%Y :%y %n’ | sort -nr | cut -d: -f2- | head
On Linux, as the original poster asked, use stat instead of gstat .
This answer is, of course, user37078’s outstanding solution, promoted from comment to full answer. I mixed in CharlesB’s insight to use gstat on Mac OS X. I got coreutils from MacPorts rather than Homebrew, by the way.
And here’s how I packaged this into a simple command ~/bin/ls-recent.sh for reuse:
#!/bin/bash # ls-recent: list files in a directory tree, most recently modified first # # Usage: ls-recent path [-10 | more] # # Where "path" is a path to target directory, "-10" is any argument to pass # to "head" to limit the number of entries, and "more" is a special argument # 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
Как найти новые файлы в Linux
Бывают случаи когда нужно посмотреть все новые, недавно измененные или созданные в произвольный период времени файлы в операционной системе Linux. Например, если вы системный администратор и создали файл конфигурации, но потом забыли где его сохранили или же просто хотите проверить не изменял ли кто-либо корневую файловую систему в последнее время.
Операционная система Linux, как всегда, радует множеством способов для решения этой задачи. В этой инструкции мы рассмотрим некоторые из них.
Поиск новых файлов в Linux
Способ 1. Утилита find
Самый распространенный способ найти новые файлы в linux — это воспользоваться утилитой find. В зависимости от ситуации и потребностей утилите передаются различные параметры, можно искать файлы в конкретном диапазоне дат, новее определенной даты или новее определенного файла. Рассмотрим все подробнее.
Можно вывести все файлы в директории и поддиректориях, а затем отсортировать по дате создания:
find /etc -type f -printf ‘%TY-%Tm-%Td %TT %p\n’ | sort -r
Но это слишком громоздко, да и не нужны нам все файлы, нам надо только новые. Следующей командой можно получить все файлы, измененные или созданные за последние 60 минут:
Чтобы найти последние измененные файлы linux за последних два дня используете параметр mtime:
Если нужно не углубляться в подкаталоги ниже третьего уровня, используйте опцию maxdepth:
find /etc -maxdepth 3 -mtime -2 -type f
Также можно задать диапазон времени, в котором был создан или изменен файл. Например, чтобы посмотреть новые файлы linux за последние семь дней, но исключая последние три дня, наберите:
find /etc -type f -mtime -7 ! -mtime -3
Все эти команды выводят только путь к файлу, но также можно посмотреть атрибуты с помощью опции —exec. Выведем подробные атрибуты новых файлов, выполнив для каждого из них утилиту ls:
find /etc -type f -mmin -120 -exec ls -al <> \;
Предыдущая команда немного сложна и запутана, намного нагляднее для этого использовать утилиту xargs:
find /etc -type f -mmin -120 | xargs ls -l
Утилита find также позволяет найти файлы новее определенного файла. Например, создадим эталонный файл:
И найдем все файлы в корневом каталоге, созданные после его него:
find / -type f -newer /tmp/test
Способ 2. ls
Этот способ намного проще первого, но за простоту мы платим гибкостью. Команда ls тоже умеет сортировать файлы в директории по дате создания. Просто выполните:
В данном случае самый новый файл будет в самом низу. Если файлов очень много можно обрезать вывод с помощью tail:
Выводы
Возможно, это еще не все способы найти новые файлы в Linux, но тут уже есть из чего выбрать лучшее решение для конкретной ситуации. Как показано в этой статье, базовые команды поиска find и ls могут получить еще большую гибкость в объединении с утилитами сортировки sort, а также фильтрации tail и grep.
Обнаружили ошибку в тексте? Сообщите мне об этом. Выделите текст с ошибкой и нажмите Ctrl+Enter.