How to sort results of Find statement by date?

get file names only ... sorted by modification day

find + sort + cut approach:

find . -regex ".*/[0-9.]+" -printf "%T@ %f\n" | sort | cut -d' ' -f2

  • %T@ - File's last modification time, where @ is seconds since Jan. 1, 1970, 00:00 GMT, with fractional part

  • %f - File's name with any leading directories removed (only the last element)


To sort in descending order:

find . -regex ".*/[0-9.]+" -printf "%T@ %f\n" | sort -k1,1r | cut -d' ' -f2

Your method can be adapted to work in simple cases. The main problem you're facing is that you're passing input to ls, but ls doesn't take any input. ls takes command line arguments. So you need to pass the output of find as arguments to ls, with a command substitution. Also, in case a directory is matched, pass -d to ls to list the directory itself and not its contents.

OLDDATA=$(ls -td $(find . -regex ".*/[0-9.]+"))

Only in simple cases, because there are two restrictions:

  1. This relies on an unquoted command substitution (and so does the use of $OLDDATA afterwards). Therefore it assumes that the file names don't contain any special characters (whitespace or wildcard characters \[*?).
  2. Some versions of ls may mangle characters that are not printable in the current locale.
  3. If the total length of the file names is too long, you'll get an error. (Note that find … -exec and xargs cannot help here, since ls must run a single time to get the order of the file names right. All they could do is hide errors and produce output that is not correctly sorted — and mangle a few more characters, in the case of xargs.)

A robust, simple way of doing this is to use zsh. It has the ability to sort wildcard matches, thanks to glob qualifiers.

setopt extended_glob
OLDDATA=(**/[0-9.]##(om))
  • Since this doesn't call any other program, there is no length limit other than available memory, and no risk of file name mangling at any point.
  • The result is a list of strings (each string being a file name), not a string, so it goes into an array variable.
  • **/ traverses subdirectories recursively, avoiding the use of find.
  • ## means “one or more of the preceding” in zsh extended glob syntax, it's analogous to + in (extended) regex syntax.
  • (om) is a glob qualifier to sort files by modification time, like ls -t.

There is notoriously no simple way to do this robustly with POSIX tools or even with GNU tools and ksh.