Linux/Unix 文件的 atime ctime mtime 属性

一、什么是 atime、ctime、mtime?

Linux/Unix 系统会为每个文件保存一些时间戳信息,我们可以根据这些时间戳来判断文件什么时候被读取过,什么时候被修改过内容,以及什么时候被修改过文件的权限。以下是 atime,ctime,mtime 三个时间戳的介绍。

  1. atime (last Access time)

    最近一次访问文件的时间,访问指的是 读取或者执行文件 / 文件夹的时间

  2. ctime (last Change time)

    最近一次 metadata 修改的时间,这里修改有两层意思:

    1. 修改文件 / 文件夹的 metadata,比如 user/group 或者访问权限(比如 chmod)
    2. 修改文件内容
  3. mtime (last Modify time)

    最近一次修改的时间,这里的修改 专指文件的内容修改

注意:

  1. 当创建文件时候,atime、ctime、mtime 都会修改为当前创建的时间
  2. 当修改文件内容的时候,ctime、mtime 都会更新为修改时间

二、如何查看文件的 atime、ctime、mtime

查看单个文件可以使用 stat 来查看:

1
2
3
4
5
6
7
8
9
> stat ./output.log                            
File: ./output.log
Size: 8 Blocks: 8 IO Block: 4096 regular file
Device: fc01h/64513d Inode: 1851173 Links: 1
Access: (0766/-rwxrw-rw-) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2020-01-03 22:59:18.272535807 +0800
Modify: 2020-01-03 23:00:04.506391646 +0800
Change: 2020-01-04 00:34:59.238825835 +0800
Birth: -

ps: macOS 默认单行显示结果,如果希望多行直观地显示,需要加上 -x 参数

常用的 ls -l 默认的是输出 mtime,如果想输出 atime 需要使用 ls -lu,ctime 需要使用 ls -lc ,可以看到这三种时间戳和上面是一致的。

1
2
3
4
5
6
> ls -l  ./output.log.log                          
-rw-rw-rw- 1 root root 8 Jan 3 23:00 ./output.log
> ls -lu ./output.log.log
-rw-rw-rw- 1 root root 8 Jan 3 22:59 ./output.log
> ls -lc ./output.log.log
-rw-rw-rw- 1 root root 8 Jan 4 00:34 ./output.log

三、可以拿这三个时间戳做什么?

我们可以通过 find 命令使用这几个属性来做过滤,比如查看 3 天以内被修改过的文件,或者 6 月之内没有修改过的旧文件。

怎么使用呢?我们拿 mtime 也就是文件修改时间来说的话,可以通过 find ./ -mtime n 进行过滤和查询,这里的 n 用来描述时间,分三种情况(以下的 “天也可以理解为 24 小时):

  • n 没有正负符号,或者说 n 天前的 当天 ,或者 n * 24 小时之前(的 24 个小时)。比如 3 表示 3 天前当天,或者 72 之前的 24 小时内修改过的文件。
  • +n 表示 n 天前那一整天 之前的所有时间,或者说(n+1) * 24 小时之前的时间。因为 n 本身表示 n 天前的那一整天,+n 表示这一整天之前,其实就是 n+1 天前
  • -n 表示 n 天前那一整天 之后的时间,或者 n24 以内的时间,也就是 [未来,n24 前],-2 表示小于 2 天内以及未来修改过的文件,或者说 48 小时内加上未来的时间段。(未来的时间不可能发生,所以也可以忽略)

如果还是有点绕,我们来看一些图例:

find ./ -mtime 2 表示 2 天前的当天,find ./ -mtime 0 表示 0 天前的当天,也就是今天,或者说 24 小时以内:

1
2
3
4
5
6
|▶mtime 0◀|         |▶mtime 2◀| 
┌─────────┬─────────┬─────────┬─────────┐
│ 24hrs │ 24hrs │ 24hrs │ 24hrs │
└─────────┴─────────┴─────────┴─────────┘
now 1 days 2 days 3 days
ago ago ago

OK,我们知道两天前的当天用 -mtime 2 表示, 那 -mtime +2 表示比 -mtime 2 更早的时间,也就是从 3 天前以前的时间,而 -mtime -2 表示比 -mtime 2 更晚的时间,也就是 48 小时内的时间。

1
2
3
4
5
6
 ◀─── -mtime -2 ────|▶mtime 2◀|────── ─mtime +2 ────────────▶
┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ 24hrs │ 24hrs │ 24hrs │ 24hrs │ 24hrs │ 24hrs │
└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
now 1 days 2 days 3 days 4 days
ago ago ago ago

到这里其实我们也可以得出 -mtime 2 等价于 -mtime 1 -mtime -3

-mtime 0-mtime -1 是否等价呢?一个是今天,一个是 一天前 之后的时间,所以理论上是不等价的,因为 -mtime -1 除了今天还包含未来的所有时间,但大部分情况下都是可以通用的,因为未来的时间还没发生,过滤文件应该没有问题(除非把系统时间调整到过去)。

我们也可以使用 find ./ -mtime +1 -mtime -5 来查找 2 天前,5 天内被修改的文件

1
2
3
4
5
6
                    |▶──── -mtime +1 -mtime -5──◀|          
┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ 24hrs │ 24hrs │ 24hrs │ 24hrs │ 24hrs │ 24hrs │
└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
now 1 days 2 days 3 days 4 days 5 days
ago ago ago ago ago

最开始我通过 man find 来查看 -mtime n 的详细使用用法,不过看完依然一头雾水。这里 ago 的意思,不是指 “之前” 所有的时间,而是 “之前” 的那一天或者是 “之前” 的 24 小时。

1
2
3
4
5
-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.

参考:

atime, ctime and mtime in Unix filesystems

Selecting files using their age