Files – How to List Files Sorted by Modification Date Recursively Without stat Command

datefilessort

How can I get the list of all files under current directory along with their modification date and sorted by that date?

Now I know how to achieve that with find, stat and sort, but for some weird reason the stat is not installed on the box and it's unlikely that I can get it installed.

Any other option?

PS: gcc is not installed either

Best Answer

My shortest method uses zsh:

print -rl -- **/*(.Om)

(add the D glob qualifiers if you also want to list the hidden files or the files in hidden directories).

If you have GNU find, make it print the file modification times and sort by that. I assume there are no newlines in file names.

find . -type f -printf '%T@ %p\n' | sort -k 1 -n | sed 's/^[^ ]* //'

If you have Perl (again, assuming no newlines in file names):

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

If you have Python (again, 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]): print f'

If you have SSH access to that server, mount the directory over sshfs on a better-equipped machine:

mkdir mnt
sshfs server:/path/to/directory mnt
zsh -c 'cd mnt && print -rl **/*(.Om)'
fusermount -u mnt

With only POSIX tools, it's a lot more complicated, because there's no good way to find the modification time of a file. The only standard way to retrieve a file's times is ls, and the output format is locale-dependent and hard to parse.

If you can write to the files, and you only care about regular files, and there are no newlines in file names, here's a horrible kludge: create hard links to all the files in a single directory, and sort them by modification time.

set -ef                       # disable globbing
IFS='
'                             # split $(foo) only at newlines
set -- $(find . -type f)      # set positional arguments to the file names
mkdir links.tmp
cd links.tmp
i=0 list=
for f; do                     # hard link the files to links.tmp/0, links.tmp/1, …
  ln "../$f" $i
  i=$(($i+1))
done
set +f
for f in $(ls -t [0-9]*); do  # for each file, in reverse mtime order:
  eval 'list="${'$i'}         # prepend the file name to $list
$list"'
done
printf %s "$list"             # print the output
rm -f [0-9]*                  # clean up
cd ..
rmdir links.tmp
Related Question