背景

有时候我们需要获取文件的创建时间。

例如:我在研究 《xtrabackup 原理图》的时候,想通过观察确认 xtrabackup_log 是最早创建 并且是 最晚保存的文件。我们就需要知道 xtrabackup_logfile 这个文件的创建时间戳修改时间戳

复习:Linux关于文件的三个时间戳

Linux 的文件系统保存有三个时间戳,利用 stat 指令查看文件信息可以获取。他们分别是 ATime、MTime 和 CTime

  1. [root@192-168-199-198 backups]# stat 2.txt

  2. File: ‘2.txt’

  3. Size: 16 Blocks: 8 IO Block: 4096 regular file

  4. Device: 821h/2081d Inode: 15 Links: 1

  5. Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)

  6. Access: 2019-07-23 12:12:14.276981038 +0800

  7. Modify: 2019-07-23 12:12:41.415980158 +0800

  8. Change: 2019-07-23 12:12:41.415980158 +0800

  9. Birth: -

  • ATime ——文件的最近访问时间

只要读取文件,ATime 就会更新,对应的是 stat 命令获取的 Access 的值。

  1. [root@192-168-199-198 backups]# cat 2.txt #<-- 读取文件

  2. 121231233123123

  3. [root@192-168-199-198 backups]# stat 2.txt

  4. File: ‘2.txt’

  5. Size: 16 Blocks: 8 IO Block: 4096 regular file

  6. Device: 821h/2081d Inode: 15 Links: 1

  7. Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)

  8. Access: 2019-07-23 12:22:09.644961733 +0800 #<-- 时间变化了

  9. Modify: 2019-07-23 12:12:41.415980158 +0800

  10. Change: 2019-07-23 12:12:41.415980158 +0800

  11. Birth: -

  • MTime ——文件的内容最近修改的时间

当文件进行被写的时候,MTime 就会更新,对应的是 stat 命令获取的 Modify 的值。
  1. [root@192-168-199-198 backups]# echo hello_world > 2.txt #<-- 修改文件内容

  2. [root@192-168-199-198 backups]# stat 2.txt

  3. File: ‘2.txt’

  4. Size: 12 Blocks: 8 IO Block: 4096 regular file

  5. Device: 821h/2081d Inode: 15 Links: 1

  6. Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)

  7. Access: 2019-07-23 12:22:09.644961733 +0800

  8. Modify: 2019-07-23 12:26:23.466953503 +0800 #<-- 时间变化了

  9. Change: 2019-07-23 12:26:23.466953503 +0800

  10. Birth: -

这里不要用vi修改文件内容,因为用vi修改文件内容有可能会引起Inode变更,也就是你观察的文件并不是之前的文件了!这个和vi的原理有关。

  • CTime ——文件属性最近修改的时间

当文件的目录被修改,或者文件的所有者,权限等被修改时,CTime 也就会更新,对应的是 stat 命令获取的 Change 的值。
  1. [root@192-168-199-198 backups]# chmod 777 2.txt #<-- 修改文件属性

  2. [root@192-168-199-198 backups]# stat 2.txt

  3. File: ‘2.txt’

  4. Size: 12 Blocks: 8 IO Block: 4096 regular file

  5. Device: 821h/2081d Inode: 15 Links: 1

  6. Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)

  7. Access: 2019-07-23 12:22:09.644961733 +0800

  8. Modify: 2019-07-23 12:26:23.466953503 +0800

  9. Change: 2019-07-23 12:30:35.830945320 +0800 #<-- 时间变化了

  10. Birth: -

Linux 无法获取文件创建时间?
现在我们知道了Linux有三种时间,ATime、MTime 和 CTime,那么很好奇为什么没有 CRTime (创建时间) 呢?
对比 Windows 系统 (上图),Windows 的 NTFS 文件系统里存在三个时间戳,其中就包含了“创建时间”,但在 Linux 的设计哲学上没有文件“创建时间”这么一说,所以早期版本的ext文件系统不支持文件“创建时间”。但从 ext4 版本开始,文件创建时间存储在ext4文件系统的inode中,所以 ext4 文件系统使用特殊方法也是可以获取文件的创建时间的。

也说明了,是否能获取文件的创建时间,和文件系统是否支持有关。

Linux 上获取文件创建时间的步骤

CentOS7 Linux系统自带一个工具,叫做 debugfs,他可以查出 ext4 文件系统上的文件的创建时间。man debugfs 发现工具的描述是 “ext2/ext3/ext4 file system debugger”,所以他是不支持 xfs 文件系统的。

常用的 xfs 文件系统是否支持获取文件创建时间,还有如何获取,这个暂时不清楚,需读者查阅官方文档

1. 获取文件的 inode 号

方法一:
  1. [root@192-168-199-198 backups]# stat /backups/2.txt

  2. File: ‘/backups/2.txt’

  3. Size: 30 Blocks: 8 IO Block: 4096 regular file

  4. Device: 821h/2081d Inode: 14 #<--- 这个 Links: 1

  5. Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)

  6. Access: 2019-07-23 12:49:11.462909146 +0800

  7. Modify: 2019-07-23 12:49:11.462909146 +0800

  8. Change: 2019-07-23 13:08:20.138871900 +0800

  9. Birth: -

方法二:
  1. [root@192-168-199-198 backups]# ls -i /backups/2.txt

  2. 14 /backups/2.txt

这里,我们获取的 inode 编号是 14。

2. 查找文件所在磁盘路径

  1. [root@192-168-199-198 backups]# df -h

  2. Filesystem Size Used Avail Use% Mounted on

  3. /dev/mapper/centos-root 46G 23G 24G 49% /

  4. devtmpfs 3.8G 0 3.8G 0% /dev

  5. tmpfs 3.9G 8.0K 3.9G 1% /dev/shm

  6. tmpfs 3.9G 12M 3.8G 1% /run

  7. tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup

  8. /dev/sdb1 100G 77G 24G 77% /data2

  9. /dev/sdc1 50G 53M 47G 1% /backups #<--- 可以看出文件在这里面

  10. /dev/sda1 1014M 142M 873M 14% /boot

  11. tmpfs 781M 0 781M 0% /run/user/0

磁盘路径为 /dev/sdc1

3. 使用debugfs 查看文件创建时间

  1. [root@192-168-199-198 backups]# debugfs -R 'stat <14>' /dev/sdc1

  2. debugfs 1.42.9 (28-Dec-2013)

  3. Inode: 14 Type: regular Mode: 0644 Flags: 0x80000

  4. Generation: 737271740 Version: 0x00000000:00000001

  5. User: 0 Group: 0 Size: 30

  6. File ACL: 0 Directory ACL: 0

  7. Links: 1 Blockcount: 8

  8. Fragment: Address: 0 Number: 0 Size: 0

  9. ctime: 0x5d369644:211c1170 -- Tue Jul 23 13:08:20 2019

  10. atime: 0x5d3691c7:6e5dbb68 -- Tue Jul 23 12:49:11 2019

  11. mtime: 0x5d3691c7:6e5dbb68 -- Tue Jul 23 12:49:11 2019

  12. crtime: 0x5d3691c7:6e5dbb68 -- Tue Jul 23 12:49:11 2019

  13. Size of extra inode fields: 28

  14. EXTENTS:

  15. (0):35337

获取文件创建时间的脚本

鉴于获取文件创建时间步骤操作有点麻烦 (虽然只有三步 :) )

我这里提供了一个脚本

vi statx

  1. #!/bin/sh


  2. [ $# -ne 1 ] && echo "Usage: $0 {FILENAME}" && exit 1


  3. INODE=`ls -i $1 |awk '{print $1}'`

  4. FILENAME=$1


  5. #如果传入参数带/,则获取这个传入参数的目录路径并进入目录

  6. `echo $FILENAME |grep / 1> /dev/null` && { FPWD=${FILENAME%/*};FPWD=${FPWD:=/};cd ${FPWD};FPWD=`pwd`; } || FPWD=`pwd`




  7. array=(`echo ${FPWD} | sed 's@/@ @g'`)

  8. array_length=${#array[@]}


  9. for ((i=${array_length};i>=0;i--))

  10. do

  11. unset array[$i]

  12. SUBPWD=`echo " "${array[@]} | sed 's@ @/@g'`

  13. DISK=`df -h |grep ${SUBPWD}$ |awk '{print $1}'`

  14. [[ -n $DISK ]] && break

  15. done




  16. #不是ext4就退出

  17. [[ "`mount |grep ${DISK} |awk '{print $5}'`" != "ext4" ]] && { echo ${DISK} is not mount on type ext4! Only ext4 file system support!;exit 2; }


  18. debugfs -R "stat <${INODE}>" ${DISK}

使用:

  1. chmod +x statx

  2. mv statx /usr/sbin/statx


  3. [root@192-168-199-198 backups]# statx 2.txt

  4. debugfs 1.42.9 (28-Dec-2013)

  5. Inode: 14 Type: regular Mode: 0644 Flags: 0x80000

  6. Generation: 737271740 Version: 0x00000000:00000001

  7. User: 0 Group: 0 Size: 30

  8. File ACL: 0 Directory ACL: 0

  9. Links: 1 Blockcount: 8

  10. Fragment: Address: 0 Number: 0 Size: 0

  11. ctime: 0x5d369644:211c1170 -- Tue Jul 23 13:08:20 2019

  12. atime: 0x5d36bb8f:56eb1e70 -- Tue Jul 23 15:47:27 2019

  13. mtime: 0x5d3691c7:6e5dbb68 -- Tue Jul 23 12:49:11 2019

  14. crtime: 0x5d3691c7:6e5dbb68 -- Tue Jul 23 12:49:11 2019

  15. Size of extra inode fields: 28

  16. EXTENTS:

  17. (0):35337

!!!请谨慎在生产环境使用,shell脚本没有做太多的异常处理,不支持管道,不支持目录也没有经过大量的测试

实战

我们回过头来,用这个方法,确认《xtrabackup 原理图》是否准确。

我们需要验证的是:

xtrabackup_log 是最早创建 并且是 最晚保存的文件
1. 创建备份
  1. DATE=`date "+%Y%m%d%H%M%S"`

  2. xtrabackup -uroot -proot \

  3. -S /tmp/mysql3306.sock \

  4. --backup \

  5. --target-dir=/backups/$DATE

2. 查找所有备份文件的crtime

  1. cd /backups/$DATE

  2. >/tmp/1.txt

  3. >/tmp/2.txt

  4. find . -type f >/tmp/1.txt


  5. for i in `cat /tmp/1.txt`

  6. do

  7. { echo -n $i" ";statx $i 2>/dev/null |grep crtime |awk '{print $7}'; } >>/tmp/2.txt

  8. done


  9. cat /tmp/2.txt |sort -k2 |less

  10. ###以下为输出###

  11. ./ibdata1 23:32:59

  12. ./xtrabackup_logfile 23:32:59 #<---可以看出这个文件是最早创建的

  13. ./mysql/engine_cost.ibd 23:33:00

  14. ./mysql/gtid_executed.ibd 23:33:00

  15. ./mysql/help_category.ibd 23:33:00

  16. ./mysql/help_keyword.ibd 23:33:00

  17. ./mysql/help_relation.ibd 23:33:00

  18. ./mysql/help_topic.ibd 23:33:00

  19. ./mysql/innodb_index_stats.ibd 23:33:00

  20. ./mysql/innodb_table_stats.ibd 23:33:00

  21. ./mysql/plugin.ibd 23:33:00

  22. ./mysql/server_cost.ibd 23:33:00

  23. ./mysql/servers.ibd 23:33:00

  24. ./mysql/slave_master_info.ibd 23:33:00

  25. ./mysql/slave_relay_log_info.ibd 23:33:00

  26. ./mysql/slave_worker_info.ibd 23:33:00

  27. ./mysql/time_zone.ibd 23:33:00

  28. ./mysql/time_zone_leap_second.ibd 23:33:00

  29. ...

  30. ./zabbix/trigger_tag.frm 23:33:09

  31. ./zabbix/users.frm 23:33:09

  32. ./zabbix/users_groups.frm 23:33:09

  33. ./zabbix/usrgrp.frm 23:33:09

  34. ./zabbix/valuemaps.frm 23:33:09

  35. ./zabbix/widget_field.frm 23:33:09

  36. ./zabbix/widget.frm 23:33:09

3. 查找所有备份文件的mtime

  1. >/tmp/1.txt

  2. >/tmp/2.txt

  3. find . -type f >/tmp/1.txt


  4. for i in `cat /tmp/1.txt`

  5. do

  6. { echo -n $i" ";statx $i 2>/dev/null |grep mtime |awk '{print $7}'; } >>/tmp/2.txt

  7. done


  8. cat /tmp/2.txt |sort -k2 |less

  9. ###以下为输出###

  10. ./ibdata1 23:33:00

  11. ./mysql/engine_cost.ibd 23:33:00

  12. ./mysql/gtid_executed.ibd 23:33:00

  13. ./mysql/help_category.ibd 23:33:00

  14. ./mysql/help_keyword.ibd 23:33:00

  15. ./mysql/help_relation.ibd 23:33:00

  16. ./mysql/help_topic.ibd 23:33:00

  17. ./mysql/innodb_index_stats.ibd 23:33:00

  18. ./mysql/innodb_table_stats.ibd 23:33:00

  19. ./mysql/plugin.ibd 23:33:00

  20. ...

  21. ./xtrabackup_logfile 23:33:09 #<---可以看出这个文件是最后修改和保存的

  22. ./zabbix/acknowledges.frm 23:33:09

  23. ./zabbix/actions.frm 23:33:09

  24. ...

  25. ./zabbix/users_groups.frm 23:33:09

  26. ./zabbix/usrgrp.frm 23:33:09

  27. ./zabbix/valuemaps.frm 23:33:09

  28. ./zabbix/widget_field.frm 23:33:09

  29. ./zabbix/widget.frm 23:33:09

最后,我们通过文件的创建时间和修改时间,实战地验证了《xtrabackup 原理图》的第一和第七步顺序的正确性。

近期社区动态