167

I'm struggling to wrap my mind around why the find interprets file modification times the way it does. Specifically, I don't understand why the -mtime +1 doesn't show files less than 48 hours old.

As an example test I created three test files with different modified dates:

[root@foobox findtest]# ls -l
total 0
-rw-r--r-- 1 root root 0 Sep 25 08:44 foo1
-rw-r--r-- 1 root root 0 Sep 24 08:14 foo2
-rw-r--r-- 1 root root 0 Sep 23 08:14 foo3

I then ran find with the -mtime +1 switch and got the following output:

[root@foobox findtest]# find -mtime +1
./foo3

I then ran find with the -mmin +1440 and got the following output:

[root@foobox findtest]# find -mmin +1440
./foo3
./foo2

As per the man page for find, I understand that this is expected behavior:

 -mtime n
        File’s  data was last modified n*24 hours ago.  See the comments
        for -atime to understand how rounding affects the interpretation
        of file modification times.


-atime n
       File  was  last  accessed n*24 hours ago.  When find figures out
       how many 24-hour periods ago the file  was  last  accessed,  any
       fractional part is ignored, so to match -atime +1, a file has to
       have been accessed at least two days ago.

This still doesn't make sense to me though. So if a file is 1 day, 23 hours, 59 minutes, and 59 seconds old, find -mtime +1 ignores all that and just treats it like it's 1 day, 0 hours, 0 minutes, and 0 seconds old? In which case, it's not technically older that 1 day and ignored?

Does... not... compute.

Mike B
  • 8,900
  • 8
    At first it seemed funny to me too, but when you consider that it measures a files age in integer days, then it does exactly what you'd expect. It won't give files equal to 1 day old. A file that is int(1.99) days old is not > 1. – Octopus Sep 19 '14 at 20:20
  • Think about how humans treat age colloquially. If somebody is 79.9 years old, you say they are 79 years old. So if you are looking for a human over 79 years old, then you are looking for a human that is > 79.99999 years old i.e. >= 80 years old. People look at age as integers and round it down and see each age as a range. – barlop May 07 '20 at 00:08

7 Answers7

120

The argument to -mtime is interpreted as the number of whole days in the age of the file. -mtime +n means strictly greater than, -mtime -n means strictly less than.

Note that with Bash, you can do the more intuitive:

$ find . -mmin +$((60*24))
$ find . -mmin -$((60*24))

to find files older and newer than 24 hours, respectively.

(It's also easier than typing in a fractional argument to -mtime for when you want resolution in hours or minutes.)

Evgeni Sergeev
  • 1,371
  • 3
  • 10
  • 9
  • 2
    To list those files (regular only) with human-readable sizes and in chronological order, do $ find . -type f -mmin -$((60*24)) -exec ls -halt {} + – Evgeni Sergeev Feb 04 '14 at 01:45
  • 2
    This will also have the same effect in that both of those commands together will still miss the files inside that one minute window 24 hours ago. – Octopus Sep 19 '14 at 20:21
  • 2
    $(()) is plain shell arithmetic syntax, it's not specific to Bash, cf. http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_04 – Josip Rodin Jul 22 '15 at 20:28
  • @JosipRodin No, not necessarily true! This chapter describes the syntax of that command language as it is used by the sh utility and [...]. Since Bash is a "extended" SH, it supports this syntax, but some other shells don't, e.g. csh/tcsh. – t0r0X Jan 29 '16 at 17:18
  • @t0r0X my point was that it's not a bashism, rather, it works in dash and zsh and whatever else serves as a conventional /bin/sh. – Josip Rodin Jan 29 '16 at 21:49
105

Well, the simple answer is, I guess, that your find implementation is following the POSIX/SuS standard, which says it must behave this way. Quoting from SUSv4/IEEE Std 1003.1, 2013 Edition, "find":

-mtime n
     The primary shall evaluate as true if the file modification time subtracted
     from the initialization time, divided by 86400 (with any remainder discarded), is n.

(Elsewhere in that document it explains that n can actually be +n, and the meaning of that as "greater than").

As to why the standard says it shall behave that way—well, I'd guess long in the past a programmer was lazy or not thinking about it, and just wrote the C code (current_time - file_time) / 86400. C integer arithmetic discards the remainder. Scripts started depending on that behavior, and thus it was standardized.

The spec'd behavior would also be portable to a hypothetical system that only stored a modification date (not time). I don't know if such a system has existed.

derobert
  • 109,670
67

Fractional 24-hour periods are truncated! That means that “find -mtime +1” says to match files modified two or more days ago.

find . -mtime +0 # find files modified greater than 24 hours ago
find . -mtime 0 # find files modified between now and 1 day ago
# (i.e., in the past 24 hours only)
find . -mtime -1 # find files modified less than 1 day ago (SAME AS -mtime 0)
find . -mtime 1 # find files modified between 24 and 48 hours ago
find . -mtime +1 # find files modified more than 48 hours ago

The following may only work on GNU?

find . -mmin +5 -mmin -10 # find files modified between
# 6 and 9 minutes ago
find / -mmin -10 # modified less than 10 minutes ago
jimmij
  • 47,140
Emir MurtaZa
  • 771
  • 5
  • 2
27

-mtime N means files whose age A in days satisfies NA < N+1. In other words, -mtime N selects files that were last modified between N and N+1 days ago.

-mtime -N means files whose age A satisfies A < N, i.e. files modified less than N days ago. Less intuitively, -mtime +N means files whose age A satisfies N+1 ≤ A, i.e. files modified at least N+1 days ago.

For example, -mtime 1 selects files that were modified between 1 and 2 days ago. -mtime +1 selects files that were modified at least 2 days ago. To get files modified at least 1 day ago, use -mtime +0.

The description “was last modified n*24 hours ago” is only an approximation, and not a very clear one.

If you find these rules hard to remember, use a reference file instead.

touch -d '1 day ago' cutoff
find . -newer cutoff

(The syntax “1 day ago” requires GNU touch.)

20

So if a file is 1 day, 23 hours, 59 minutes, and 59 seconds old, find -mtime +1 ignores all that and just treats it like it's 1 day, 0 hours, 0 minutes, and 0 seconds old?

Yes. Like man find says, "any fractional part is ignored". If you divide "1 day, 23 hours, 59 minutes, and 59 seconds" through "24 hours", you may get 1.9999, but the .9999 part is then stripped and suddenly the file is only 1 day old.

4

Use -mmin, -amin, etc to get exact results

Eran Ben-Natan
  • 568
  • 2
  • 7
-3

If you want exactly 48-hours-old files, not 2 days, then you should add --daystart in your find command. This will help you.

find . type -f -daystart -mtime +1
  • 5
    No, first it's -daystart (a GNU extension), not --daystart. Then, -daystart just means to compare times with the beginning of today instead of the current time, so --daystart -mtime +1 would report files that were modified more that 48h / 2 hours before the beginning of the today, so usually files that were modified strickly before the day before yesterday. – Stéphane Chazelas Jan 13 '16 at 10:24