Find the latest file by modified date

You do not need to recur to external commands (as ls) because find can do all you need through the -printf action:

find /path -printf '%T+ %p\n' | sort -r | head

I had a similar problem today, but I attacked it without find. I needed something short I could run over ssh to return the most recently edited file in my home directory. This is roughly what I came up with:

ls -tp | grep -v /$ | head -1

The -p option to ls adds a trailing slash to directories, the grep -v removes lines ending in a slash (aka, all directories), and the head -1 limits the output to a single file.

This is much less verbose than using find if all you want to return is the file name.


This is on my system faster than printf, though I don't understand why

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head

EDIT: I guess this post is not 'not particularly useful' as I thought it was. This is a really fast solution that just keeps track of the most recently modified file (instead of sorting the entire list of files):

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

Spread over multiple lines for clarity it looks as follows:

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

End of EDIT


Not a particularly useful post but since 'arrange' was discussing speed, I thought I'd share this.

arrange's and enzotib's solutions involve listing all files inside the directory with their mtimes and then sorting. As you know sorting is not necessary to find the maximum. Finding maximum can be done in linear time but sorting takes n log(n) time [I know the difference isn't much, but still ;)]. I can't think of a neat way of implementing this. [EDIT: A neat (albeit dirty looking) and fast implementation provided above.]

Next best thing - To find the most recently edited file in a directory, recursively find the most recently edited file in each level 1 subdirectory. Let this file represent the subdirectory. Now sort the level 1 files along with the representatives of the level 1 subdirectories. If the number of number of level 1 files and sub-dirs of each directory is nearly a constant, then this process should scale linearly with total number of files.

This is what I came up with to implement this:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

I ran this and got a bunch of find: findrecent: No such file or directory errors. Reason: -exec of find runs in a different shell. I tried defining findrecent in .bashrc, .xsessionrc but these didn't help [I'd appreciate help here]. In the end I resorted to putting

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

in a script called findrecent in my PATH and then running it.

I ran this, kept waiting and waiting with no output. Just to be sure I wasn't dealing with any infinite loops I modified the file to

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

and tried again. It did work - but took 1 minute 35 seconds on my homefolder - arrange's and enzotib's solutions took 1.69, 1.95 seconds respectively!

So much for O(n)'s superiority over O(n log (n))! Damn you function call overhead! [Or rather script call overhead]

But this script does scale better than the earlier solutions and I bet it'll run faster than them on google's memory bank ;D


Use perl in conjonctin with find :

 find my_directory -type f -printf '%T@\t%p\n' | perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

You get the name of the file with the greatest epoch == last file modified.