Unix/Linux find and sort by date modified
Solution 1
Use this:
find . -printf "%T@ %Tc %p\n" | sort -n
printf
arguments from man find
:
%Tk
: File's last modification time in the format specified byk
.@
: seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.c
: locale's date and time (Sat Nov 04 12:02:33 EST 1989).%p
: File's name.
Solution 2
The easiest method is to use zsh, thanks to its glob qualifiers.
print -lr -- $dir/**/$str*(om[1,10])
If you have GNU find, make it print the file modification times and sort by that.
find -type f -printf '%T@ %p\0' |
sort -zk 1nr |
sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10
If you have GNU find but not other GNU utilities, use newlines as separators instead of nulls; you'll lose support for filenames containing newlines.
find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^ ]* //' | head -n 10
If you have Perl (here I'll assume there are no newlines in file names):
find . -type f -print |
perl -l -ne '
$_{$_} = -M; # store file age (mtime - now)
END {
$,="\n";
@sorted = sort {$_{$a} <=> $_{$b}} keys %_; # sort by increasing age
print @sorted[0..9];
}'
If you have Python (also assuming no newlines in file names):
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], reverse=True))[:10]: print f'
There's probably a way to do the same in PHP, but I don't know it.
If you want to work with only POSIX tools, it's rather more complicated; see How to list files sorted by modification date recursively (no stat command available!) (retatining the first 10 is the easy part).
Solution 3
You don't need to PHP or Python, just ls:
man ls:
-t sort by modification time
-r, reverse order while sorting (--reverse )
-1 list one file per line
find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;
If command * exits with a failure status (ie Argument list too long), then you can iterate with find. Paraphrased from: The maximum length of arguments for a new process
-
find . -print0|xargs -0 command
(optimizes speed, if find doesn't implement "-exec +" but knows "-print0") -
find . -print|xargs command
(if there's no white space in the arguments)
If the major part of the arguments consists of long, absolute or relative paths, then try to move your actions into the directory: cd /directory/with/long/path; command *
And another quick fix may be to match fewer arguments: command [a-e]*; command [f-m]*; ...
Solution 4
Extending user195696's answer:
find . -type f -printf "%T@\t%Tc %6k KiB %p\n" | sort -n | cut -f 2-
For each file, this first outputs the numeric timestamp (for sorting by, followed by tabulation \t
), then a human-readable timestamp, then the filesize (unfortunately find
's -printf
can't do in mebibytes, only kibibytes), then the filename with relative path.
Then sort -n
sorts it by the first numeric field.
Then cut
gets rid of that first numeric field which is of no interest to the user. (Prints second field onward.) The default field separator is \t
or tabulation.
Example of output:
Thu 06 Feb 2014 04:49:14 PM EST 64 KiB ./057_h2_f7_10/h2_f7_10.class
Fri 07 Feb 2014 02:08:30 AM EST 7962976 KiB ./056_h2_f7_400/h2__rh_4e-4.mph
Fri 07 Feb 2014 02:23:24 AM EST 7962976 KiB ./056_h2_f7_400/h2_f7_400_out_Model.mph
Fri 07 Feb 2014 02:23:24 AM EST 0 KiB ./056_h2_f7_400/h2_f7_400_out.mph.status
Fri 07 Feb 2014 02:23:24 AM EST 64 KiB ./056_h2_f7_400/1579678.out
Fri 07 Feb 2014 03:47:31 AM EST 8132224 KiB ./057_h2_f7_10/h2__rh_1e-5.mph
Fri 07 Feb 2014 04:00:49 AM EST 8132224 KiB ./057_h2_f7_10/h2_f7_10_out_Model.mph
Fri 07 Feb 2014 04:00:49 AM EST 0 KiB ./057_h2_f7_10/h2_f7_10_out.mph.status
Fri 07 Feb 2014 04:00:49 AM EST 64 KiB ./057_h2_f7_10/1579679.out
Fri 07 Feb 2014 09:47:18 AM EST 9280 KiB ./056_h2_f7_400/h2__rh_4e-4.mat
Fri 07 Feb 2014 10:51:23 AM EST 9728 KiB ./018_bidomain/h2_plain__rh_1e-5.mat
Fri 07 Feb 2014 10:58:33 AM EST 9568 KiB ./057_h2_f7_10/h2__rh_1e-5.mat
Fri 07 Feb 2014 05:05:38 PM EST 64 KiB ./058_h2_f7_stationary/h2_f7_stationary.java
Fri 07 Feb 2014 06:06:29 PM EST 32 KiB ./058_h2_f7_stationary/slurm.slurm
Sat 08 Feb 2014 03:42:07 AM EST 0 KiB ./058_h2_f7_stationary/1581061.err
Sat 08 Feb 2014 03:42:14 AM EST 64 KiB ./058_h2_f7_stationary/h2_f7_stationary.class
Sat 08 Feb 2014 03:58:28 AM EST 70016 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mph
Sat 08 Feb 2014 04:12:40 AM EST 70304 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mph
Sat 08 Feb 2014 04:12:53 AM EST 70304 KiB ./058_h2_f7_stationary/h2_f7_stationary_out_Model.mph
Sat 08 Feb 2014 04:12:53 AM EST 0 KiB ./058_h2_f7_stationary/h2_f7_stationary_out.mph.status
Sat 08 Feb 2014 04:12:53 AM EST 32 KiB ./058_h2_f7_stationary/1581061.out
Mon 10 Feb 2014 11:40:54 AM EST 224 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mat
Mon 10 Feb 2014 11:42:32 AM EST 224 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mat
Mon 10 Feb 2014 11:50:08 AM EST 32 KiB ./plot_grid.m
I deliberately made the filesize field 6 characters, because if making it longer, it becomes hard to visually distinguish how large the files are. This way, files larger than 1e6 KiB jut out: by 1 char means 1-9 GB, by 2 chars means 10-99 GB, etc.
Edit: here's another version (since find . -printf "%Tc"
crashes on MinGW/MSYS):
find . -type f -printf "%T@\t%p\n" | sort -n | cut -f 2- | xargs -I{} ls -Glath --si {}
Giving output like:
-rw-r--r-- 1 es 23K Jul 10 2010 ./laptop_0000071.jpg
-rw-r--r-- 1 es 43M Jul 29 19:19 ./work.xcf
-rw-r--r-- 1 es 87K Jul 29 20:11 ./patent_lamps/US Patent 274427 Maxim Lamp Holder.jpg
-rw-r--r-- 1 es 151K Jul 29 20:12 ./patent_lamps/Edison screw-in socket.png
-rw-r--r-- 1 es 50K Jul 29 20:13 ./patent_lamps/1157 Lamp.jpg
-rw-r--r-- 1 es 38K Jul 29 20:14 ./patent_lamps/US06919684-20050719-D00001.png
Where:
-I{}
causes the occurrence of{}
to be replaced by an argument, and newlines are now the argument separators (note the spaces in filenames above).ls -G
suppresses printing the group name (waste of space).ls -h --si
produces human-readable file sizes (more correct with--si
).ls -t
sorts by time, which is irrelevant here, but that's what I typically use.
Solution 5
I have a simple solution that works for both FreeBSD (OS X) and Linux:
find . -type f -exec ls -t {} +
Related videos on Youtube
Peter Mortensen
Updated on September 18, 2022Comments
-
Peter Mortensen almost 2 years
How can I do a simple
find
which would order the results by most recently modified?Here is the current
find
I am using (I am doing a shell escape in PHP, so that is the reasoning for the variables):find '$dir' -name '$str'\* -print | head -10
How could I have this order the search by most recently modified? (Note I do not want it to sort 'after' the search, but rather find the results based on what was most recently modified.)
-
occulus almost 12 yearsIf there are a lot of files, this fails with 'Argument list too long' on the ls. Maybe recook to use xargs?
-
occulus almost 12 yearsIf there are a lot of files, this fails with 'Argument list too long' on the ls.
-
Ярослав Рахматуллин almost 12 yearsThat's true, but I believe the question was "how do I do a simple find..."
-
Ivan Vučica about 11 yearsSadly, this prints out localized month names on my Croatian setup, making sort incorrect.
-
Jake N about 11 years+1 Very useful, the first answer to this I have found with a readable/useful date output
-
jan almost 10 yearsI improved this sript to handle whitespace in filenames, see superuser.com/a/777007/134532
-
Tobu over 9 yearsls doesn't quote file names in a way xargs can understand (no -0 option, and the various quote styles are inadequate)
-
Evgeni Sergeev over 9 yearsNote: to sort by file size instead, simply replace the
T@
bys
in either of the above commands. -
Kef Schecter almost 9 yearsMy sed says it doesn't have a -z option.
-
Gilles 'SO- stop being evil' almost 9 years@KefSchecter Then use newlines as separators, but you'll lose support for newlines in file names.
-
Aaron D. Marasco over 8 yearsBut if
xargs
callsls
multiple times, the sort will be broken. -
joelostblom over 7 yearsI have this alias for finding recent files in my
~/.zshrc
:fr () { find ./ -iname "*"$@"*" -printf "%T@ %Td-%Tb-%TY %Tk:%TM %p\n" | sort -n | cut -d " " -f 2- | grep -i "$@" ; }
It recursively finds all files containing the pattern of the first argument passed to the command (fr <pattern>
) and sorts them with the most recent one last. -
Peter Mortensen over 7 yearsuser195696's answer works for the Croatian setup (and others).
-
DavidPostill over 7 yearsThis doesn't sort by date modified.
-
Goblinhack over 6 yearsThe above is for python2. If you only have python3, some small changes: python3 -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.keys(), key=lambda f:times[f], reverse=True))[:10]: print(f);'
-
user74094 over 6 yearsThis fails for files with spaces in their names. Any advice?
-
Varun Chandak over 5 yearsThis is great !!! To use with symlinks, use
find -L ...
-
Ludovic Kuty over 5 yearsYou may want to use
ssed
to get rid of the seconds fractional part and stil use ISO8601 as @PeterMortensen showed :find . -type f -printf "%TY-%Tm-%TdT%TT %p\n" | sort -r | ssed -R 's/^([^.]+)\.\d+ (.*)$/\1 \2/'
-
Ludovic Kuty over 5 years@joelostblom JFYI, instead of
cut -d " " -f 2-
you may want to usecut -d " " -f 1 --complement
but it is longer. -
RocketNuts over 5 yearsJust stumbled upon this answer and it was exactly what I needed in a similar situation. Question: what does the
+;
at the end do? It seems to give the same result without the;
however it does not work without the+
? -
Premium about 5 yearsThis is just the same as another answer posted 8 months before, except for the part about using "ls -1rt `find …`", which is broken
-
Peter Mortensen about 5 yearsFor ISO 8601 date output with time zone information, use
find . -printf "%TY-%Tm-%TdT%TT %TZ %p\n"
. As it sorts naturally, it can also, like the Unix time in this answer, be used directly in the sort:find . -printf "%TY-%Tm-%TdT%TT %TZ %p\n" | sort -n
. Note that the date information is not in ISO 8601 format (e.g. "CEDT" - Central European Daylight Time). (My original comment (now deleted) had a number of flaws, in particular the use of the access time instead of the modification time.) -
digitaltoast about 5 yearsThis works perfectly - should be correct answer, or at least higher rated!
-
F. Hauri almost 5 years
cut -d ' ' -f 2
will break if filenames contain spaces. -
jturi over 4 years
find . -type f -exec ls -lat {} +
gives you a better picture with date and time showing if somebody needs this format -
Sumomo over 3 yearsThis blog post explains and expands on the solution: elsewebdevelopment.com/…
-
ttq about 3 yearsNote that for OSX one has to use the GNU version
gfind
instead offind
, sinceprintf
is not part ofPOSIX
find
. It can be installed withbrew install findutils
. -
mekb almost 3 yearsthis one seems to be the quickest
-
phdoerfler over 2 yearsgetting the error
paths must precede expression
? Make sure you got-printf
and not-print
-
HKTonyLee over 2 yearsThis should be the best answer. Simple, easy to understand. The key is the plus sign in the end. This allows the
find
to callls
once only. -
Wermerb about 2 yearsYour #2 solution works (it's the only one I've tried). The answer checked as "valid" doen't work properly (not the last touched files).