跳转至

使用find查找修改时间问题记录

撰写数据库备份脚本,备份后直接清理规定时间前的文件,发现没有达到预期的清理

问题出在find -mtime命令使用上,这里记录下过程

问题描述

脚本逻辑:

  1. 数据库按照库名分别备份,方便按需恢复
  2. 备份后清理3天前的备份文件
  3. 按照[库名]-[主机IP]-[时间].sql存储

大概实现:

Bash
1
2
3
4
5
6
7
8
db1-192.168.1.10-2026-01-08-23-00.sql
db1-192.168.1.10-2026-01-09-23-00.sql
db1-192.168.1.10-2026-01-10-23-00.sql
...
db2-192.168.1.10-2026-01-08-23-11.sql
db2-192.168.1.10-2026-01-09-23-11.sql
db2-192.168.1.10-2026-01-10-23-11.sql
...

这里直接贴上 有问题的 删除备份阶段的脚本执行逻辑:

Bash
...
# 上边是备份过程
# ------下边开始清理部分------
# 下边变量具体使用时自定义
# 备份目录
BACKUP_DIR="/back"
# 备份的数据库名字
DATABASES="db1 db2 .."
# 主机IP
HOST_IP="192.168.1.10"
# 清理时间
RETENTION_DAYS=3
# 删除统计
DELETED_COUNT=0

# 开始遍历数据库名字
for DATABASE in `echo $DATABASES`;do
  # 查找旧文件,定义数组
  OLD_FILES=($(find "$BACKUP_DIR" -name "${DATABASE}-${HOST_IP}-*.sql" -type f -mtime +${RETENTION_DAYS}))
    # 如果有的话,遍历数组,开始挨个删除
    if [ ${#OLD_FILES[@]} -gt 0 ]; then
        echo "数据库 $DATABASE 的旧备份文件:"
        for FILE in "${OLD_FILES[@]}"; do
            echo "  删除: $(basename $FILE)"
            rm -f "$FILE"
            # 这个变量是统计一共删除多少个文件
            DELETED_COUNT=$((DELETED_COUNT + 1))
        done
    fi
done

上边逻辑是:查找备份目录中3天前修改-mtime过的数据库文件

出现的问题: 只删除了db1 8号的文件,还有 db2的8号文件没有删除

问题分析

find命令的-mtime选项是基于文件修改时间与当前时间相差的天数来计算的,而备份脚本运行时间可能不是完全精确到同一时刻,导致一些文件因为时间差没有被清理。

查看文件修改时间

Bash
root@pts/0 # stat db1-192.168.1.10-2026-01-08-23-00.sql
  文件:"db1-192.168.1.10-2026-01-08-23-00.sql"
  大小:4835343426  块:9444032    IO 块:1048576 普通文件
设备:29h/41d Inode:9873798     硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
最近访问:2026-01-08 23:00:59.397704912 +0800
最近更改:2026-01-08 23:00:59.397704912 +0800
最近改动:2026-01-08 23:00:59.397704912 +0800
创建时间:-
root@pts/0 # stat db2-192.168.1.10-2026-01-08-23-11.sql
  文件:"db2-192.168.1.10-2026-01-08-23-11.sql"
  大小:13189636   块:25768      IO 块:1048576 普通文件
设备:29h/41d Inode:9873788     硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
最近访问:2026-01-08 23:11:49.534381670 +0800
最近更改:2026-01-08 23:11:49.534381670 +0800
最近改动:2026-01-08 23:11:49.534381670 +0800
创建时间:-

可以看到 db1的时间在2026-01-08 23:00:59 db2的时间在2026-01-08 23:11:49

因为数据实时变化,每天执行备份的实际时间不等,假如脚本在23:10就执行到了删除阶段,此时查找3天前的文件,db2就会忽略过去,因为它的修改时间在23:11,而23:10这个时间只能找到db1的文件,此时的删除则不是我们预期的将db1、db2的8号文件全部删除

命令优化

既然找到了原因所在,我们可以修改命令使用方式,改为分钟级查找-mmin

可以这样使用

Bash
1
2
3
4
5
6
# 定义删除天数
RETENTION_DAYS=3
# 计算成分钟(3 * 24 * 60),还是23:10,在减去30分钟,变成23:40,此时会包含db2的文件
OLD_DATE=$((RETENTION_DAYS * 24 * 60 - 30))

find "$BACKUP_DIR" -name "${DATABASE}-${HOST_IP}-*.sql" -type f -mmin +${OLD_DATE}

命令演示

这里演示一下,准备4个文件

Bash
1
2
3
4
5
root@pts/0 # ll test*
-rw-r--r-- 1 root root 0 1月  16 13:25 test1
-rw-r--r-- 1 root root 0 1月  16 13:26 test2
-rw-r--r-- 1 root root 0 1月  16 13:27 test3
-rw-r--r-- 1 root root 0 1月  16 13:28 test4

使用-mmin打印一下结果

Bash
# 如下命令都是在13:31分之内执行,注意观察5、+5、-5输出的变化

# 5: 打印指定时间正好的文件
test-server [~] 2026-01-16 13:31:27
root@pts/0 # find ./ -name "test*" -mmin 5
./test3

# +5: 打印指定时间 之前的文件
test-server [~] 2026-01-16 13:31:39
root@pts/0 # find ./ -name "test*" -mmin +5
./test1
./test2

# -5: 打印指定时间 之后的文件
test-server [~] 2026-01-16 13:31:43
root@pts/0 # find ./ -name "test*" -mmin -5
./test3
./test4

统计脚本执行时间

Bash
#!/bin/bash

# 结尾计算备份时长
START_TIME=$(date +%s)

....  # 脚本执行过程

# 脚本执行完记录时间
END_TIME=$(date +%s)
# 计算时间差
EXECUTION_TIME=$((END_TIME - START_TIME))

# 打印时换算成秒
echo "脚本执行耗时: ${EXECUTION_TIME}秒 ($(($EXECUTION_TIME/60))$(($EXECUTION_TIME%60))秒)"

结果输出展示

Bash
脚本执行耗时: 13秒 (0分13秒)

统计脚本执行时间,可以方便find查找时间差