8

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.

mahela007
  • 193

3 Answers3

12

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.

terdon
  • 242,166
  • That's what I'm doing as well (with the time first). It also needs GNU findutils. – chexum Dec 25 '15 at 14:36
  • @chexum ah yes, thanks. I keep forgetting that -printf isn't POSIX. – terdon Dec 25 '15 at 14:39
  • thanks for the explanation. Can I modify this command to print the modify times in human readable format? – mahela007 Dec 26 '15 at 04:05
  • @mahela007 yes. You'd need to use date to reformat it: find -printf '%T@ %p\t\n' | sort -gk1,1 | sed -E "s/([^ ]*)/$(date -d \1)/". See updated answer. I also fixed the (completely unnecessary) use of tabs. – terdon Dec 26 '15 at 23:11
  • @mikeserv indeed I wasn't, thanks. It should work now. – terdon Dec 26 '15 at 23:23
6

With zsh:

print -rl -- **/*(D.om)

**/* match any level of subdirectories (and not follow symlinks). D. qualifiers list regular files, om sort them by modification time, newest first.

If you want the file names to be listed without the directory part, add the t history modifier:

print -rl -- **/*(D.om:t)
cuonglm
  • 153,898
2

well, if you're talking about many many thousands of files - and so beyond your ARG_MAX limit - then it won't come out so well, but the most simple solution is:

find . ! -type d -exec ls -t {} +

...which will call ls for every batch of <=ARG_MAX files which it can find. There are no arbitrary restrictions on the characters in the pathnames, either, just on the maximum number of arguments which might be processed together.

It will write output identically to find's output. You can use any other option, of course, such as -l or GNU's -h. Here are a few it listed from a small tree I created a week ago:

find . ! -type d -exec ls -lht {} +

-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 19:00 ./dir/dir1/file
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 19:00 ./dir/dir2/file
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 19:00 ./dir/dir3/file
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 19:00 ./dir2/dir1/file
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 19:00 ./dir2/dir2/file
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 19:00 ./dir2/dir3/file
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 18:57 ./dir/file1
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 18:57 ./dir/file2
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 18:57 ./dir/file3
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 18:57 ./dir2/file1
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 18:57 ./dir2/file2
-rw-r--r-- 1 mikeserv mikeserv   0 Dec 19 18:57 ./dir2/file3

...which are quite obviously not grouped by directory.

On my machine...

getconf ARG_MAX

2091752

...but I don't think that's realistic. I think it's something more like 65k or so on average.

mikeserv
  • 58,310