How to sort "find" results, based on last modification date [duplicate]

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 by k.

  • @: 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:

You do only need ls

You could do find /wherever/your/files/hide -type f -exec ls -1rt "{}" +; as stated above,

or

ls -1rt `find /wherever/your/file/hides -type f`