2

I needed to display a list of directories sorted by their creation date and I came up with this code snippet that I thought was kind of clever. Is there a more obvious way to do this that I'm missing?

printf "%-20s\t\t\t%-s\n" "DATE" "CASE"
printf "%-20s\t\t\t%-s\n" "----" "----"

find $idir -mindepth 3 -maxdepth 3 -type d -printf "%T@ %Tc\t\t%p\n" \
     | sed "s#${idir}/##" \
     | sort -h \
     | sed "s#^[^ ]* ##"

Sample output

DATE                                    CASE
----                                    ----
Fri 06 Sep 2013 11:17:41 AM EDT         dir1/Baseline/2013_09_06_11_16_10
Fri 06 Sep 2013 01:44:38 PM EDT         dir2/Baseline/2013_09_06_13_42_48
Sun 08 Sep 2013 05:02:46 PM EDT         dir3/6 Month/2013_09_08_17_02_05
Fri 13 Sep 2013 02:28:30 PM EDT         dir4/Baseline/2013_09_13_14_25_09

Details

The above will look exactly 3 directories deep from the directory $idir. It then prints the creation time of any directories that are found at this depth. I then strip the $idir portion of the path off of the output (don't need it), sort it, and then chop off the %T@ portion of the output. This was only so that I could more easily sort the output.

Without the trailing sed the output looks like this:

DATE                                    CASE
----                                    ----
1378480661.2612650000 Fri 06 Sep 2013 11:17:41 AM EDT           dir1/Baseline/2013_09_06_11_16_10
1378489478.3223970000 Fri 06 Sep 2013 01:44:38 PM EDT           dir2/Baseline/2013_09_06_13_42_48
1378674166.7427782000 Sun 08 Sep 2013 05:02:46 PM EDT           dir3/6 Month/2013_09_08_17_02_05
1379096910.4431689000 Fri 13 Sep 2013 02:28:30 PM EDT           dir4/Baseline/2013_09_13_14_25_09

Showing me a cleaner method!

slm
  • 369,824

1 Answers1

4

There is no good, portable method to sort files by their time. The most portable methods are:

  • If you can assume that file names contain only printable characters, call ls -ltd.
  • Otherwise, use perl.

This is the classical method to sort files by date with GNU tools. You're assuming that the file names contain no newline; this is easily fixed by changing \n to \0 and calling sort with the -z option. Oh, and drop the roundabout sed calls; note that your script won't work if $idir contains any of #*^$\[ because sed will interpret them as special characters.

cd "$idir" &&
find -mindepth 3 -maxdepth 3 -type d -printf '%T@ %Tc\t\t%p\0' |
sort -hz |
tr '\0\n' '\n\0' |
sed 's/^[^ ]* //'

By the way, you are sorting files by their modification time, not by their creation time. Most unix variants other than OSX do not support creation times all the way through (from the filesystem through the kernel to userland tools).

The easy, clean way to sort files by their modification time is to use zsh. The glob qualifier om sorts files in increasing age (use Om to get the oldest file first).

files=(*(om))
echo "The oldest file is $files[-1]"

To get some output like what you show, you can use zstat.

zmodload zsh/stat
describe () {
  typeset -A st
  zstat -s -H st "$REPLY"
  echo "$st[mtime] $REPLY"
}
: */*/*(/+describe)
slm
  • 369,824
  • Thanks I completely missed the access time in the man page. So find doesn't give you access to the create time? Any idea why that is? Seems odd that that would be omitted. – slm Oct 10 '13 at 01:25
  • Also I've seen you and Stephane mention the caution around files with \n. Is that really a concern? Until this week I hadn't even realized that \n was a valid character in a file name. – slm Oct 10 '13 at 01:28
  • @slm Creation time is a fairly recent thing that hasn't yet fully made its way into GNU find. It cannot be retrieved by the stat syscall, unlike the classic time trilogy (access, modification, inode change) — you need to use the recent xstat syscall. On OSX, -Btime and friends work, but find has no -printf option. – Gilles 'SO- stop being evil' Oct 10 '13 at 01:40
  • Regarding newlines in file names, see Newlines in filenames – Gilles 'SO- stop being evil' Oct 10 '13 at 01:40