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
Neither ack
or grep
have any notion of a file's modification dates. For that you'll need to generate the list of files first, and then sort them based on afterwards.
You can use xargs
to run the output of either ack
or grep
into another command which will provide the modification dates. For the modification dates you can use stat
to do that.
Example
$ grep -Rl awk * | xargs -n 1 stat --printf "%y ------ %n\n"
2013-11-12 10:06:16.000000000 -0500 ------ 100855/tst_ccmds.bash
2013-11-13 00:32:11.000000000 -0500 ------ 100911/cmd.bash
2013-11-23 03:16:17.000000000 -0500 ------ 102298/cmd.bash
2013-12-14 20:06:04.467708173 -0500 ------ 105159/cmd.txt
2013-12-16 03:20:48.166016538 -0500 ------ 105328/cmds.txt
2013-01-14 14:17:39.000000000 -0500 ------ 106932/red5-1.0.1.tar.gz
NOTE: This method will only show you the names of the files that matched your query along with the modification date.
Best Answer
It's a lot easier if you sort the list when you build it. But if you can't…
A classic approach is to add the sort criterion to the data, then sort it, and then remove the added cruft. Build an array containing timestamps and file names, in a way that is unambiguous and with the timestamps in a format that can be sorted lexicographically. Sort the array (using the
o
parameter expansion flag), then strip the prefix. You can use thestat
module to obtain the file's modification time.The
%N
format to zstat (to get timestamps at nanosecond resolution) requires zsh ≥5.6. If your zsh is older, remove it and the code will still work, but comparing timestamps at a 1-second resolution. Many filesystem have subsecond resolution, but I don't think you can get it with the zshstat
module in older versions of zsh.If your zsh is too old, you can get more precise timestamps with the
stat
utility from GNU coreutils. If you have it, you probably have the other GNU coreutils as well, so I'll use those. GNU coreutils are typically present on non-embedded Linux, but might not be on BSD or macOS. On macOS, you can install them usingbrew
. If the GNU coreutils aren't part of the base operating system, you may need to changestat
togstat
,sort
togsort
andcut
togcut
.An alternative zsh approach is to build a pattern that includes all the files in
$files
and more. Sort the files matching this pattern, then filter it to include only the desired files. You do need to build the whole pattern formore_files
, which may not always be practical.