0

I'm trying to group files by the quadrant of their creation. What I'm trying to do is determine when a file was created - for example, if I had a file that looks like this:

-rwxr-xr-x 1 root wheel 208 Aug 30 16:24 q.sh

I'd like the output to be nothing but the month it was created - in this case, 8.

Once I figure this value out, I can toss it into a simple case statement which will sort it - currently I came up with this:

#FILE_DATE would be the value I figure out above
case $FILE_DATE in
 [1-3])
        echo "Quadrant 1"
        ;;
[4-6])
        echo "Quadrant 2"
        ;;
[7-9])
        echo "Quadrant 3"
        ;;
[10-12])
        echo "Quadrant 4"
        ;;
esac

I've tried using the stat command, as well as filtering output of ls, but have not figured out how to do this reliably.

Any help would be greatly appreciated.

Thanks!

PGEL
  • 137
  • 6
    File creation time is not stored in most UNIX/Linux filesystems. – Romeo Ninov Aug 30 '21 at 13:41
  • 2
    Additionally in this context [10-12] is equivalent to [0-12]. It matches a single character, in this case 0, 1, 2 or any character between 0 and 1 in the current locale. Usually 0 directly precedes 1, so the whole expression is equivalent to [012] and matches 0, 1 or 2 only. You probably want 1[0-2] or straightforward 10|11|12. – Kamil Maciorowski Aug 30 '21 at 14:06

1 Answers1

1

With GNU date, you can do:

quadrant=$(( $(date -r "$file" +'(%-m - 1) / 3 + 1') ))

To get the quadrant in which a file was last modified.

In zsh, you could add a byquadrant glob sort order as:

zmodload zsh/stat
byquadrant() {
  local month
  stat -A month -F %-m +mtime -- ${1-$REPLY}
  REPLY=$(( (month - 1) / 3 + 1 ))-$REPLY
}

To use as:

ls -ldU -- *(o+byquadrant)

for instance (here using GNU ls's -U to disable ls's own sorting) to sort by quadrant, and then by filename within the same quadrant.

The byquadrant function returns a string that is made of the quadrant number followed by - and the original file name, and that's what we tell zsh to order that glob om using the o+<functionname> glob qualifier.

For symlinks, zsh's stat (like GNU date -r) by default retrieves the mtime of the target of the symlink. Add -L if you want the mtime of the symlink itself.

If you wanted to use the GNU implementation of stat (which postdates zsh's by a few years and is incompatible, and even incompatible with GNU find's -printf which predates it by decades and is much less usable), you'd need to output it in one of the two timestamp formats it support (iso8601 or raw epoch time) and extract the month some other way.

Could be for instance with GNU date again:

quadrant=$(( $(
    set -o pipefail
    stat -c%y -- "$file" | date -f - +'(%-m - 1) / 3 + 1'
  ) ))

Note that GNU stat by default gets you the mtime of the symlink instead of its target (the opposite of zsh stat). -L to change it.

It also doesn't work for a file called -.

With recent versions of GNU stat on recent versions of Linux, you can also use %w instead of %y to get the birth time of the file where available (as displayed with recent versions of GNU ls with ls -l --time=birth), though I find it's less useful as a creation time than the last modification time (which can be seen as the creation time of the contents of the file).