Flatten the output of a recursive directory listing

fileslsrecursive

Is there a way to list out all the files within a directory tree in a single list, sorted by modification time on Linux?

ls -Rlt 

lists out files recursively, but they are grouped under different folders in the output and as a result, the output isn't sorted as a whole. Only the contents of each directory are sorted by time.

Best Answer

Yes, you can do this with GNU find. If your file names don't contain newlines, you can do:

find -printf '%T@ %p\n' | sort -gk1,1

Explanation

  • The -printf option of find can print all sorts of information. In this case, we are using:

    %Tk    File's last modification time in the format specified  by
           k, which is the same as for %A.
    @      seconds  since Jan. 1, 1970, 00:00 GMT, with fractional part.
    %p     File's name.
    

    So, %T@ %p\n will print the file's modification time in seconds since the epoch (%T@), a space, and then the file's name (%p).

  • These are then passed to sort which is told to sort numerically (-n) on the first field only (-k1,1).

Note that this will return all files and directories. To restrict it to regular files only (no directories, device files, links etc.) add -type f to your find command.

To get human readable dates, you can process the output with GNU date:

find -printf '%T@ %p\t\n' | sort -gk1,1 | 
    perl -lne 's/([^ ]*)//;chomp($i=`date -d \@$1`); print "$i $_"'

Here, the perl command replaces the first string of non-space characters (the date) with itself as processed by GNU date.


The above will fail for file names that contain newlines. To deal with newlines, use:

find -printf '%p\t%T@\0' | sort -zt$'\t' -nk2 | tr '\0' '\n'

That's the same thing except that find will output a \0 instead of \n at the end of each file name. GNU sort can deal with null-separated output so it is still able to sort correctly. The final tr command translates the \0 back to \n.