使用find查找修改时间问题记录
撰写数据库备份脚本,备份后直接清理规定时间前的文件,发现没有达到预期的清理
问题出在find -mtime命令使用上,这里记录下过程
问题描述
脚本逻辑:
- 数据库按照库名分别备份,方便按需恢复
- 备份后清理3天前的备份文件
- 按照
[库名]-[主机IP]-[时间].sql存储
大概实现:
| Bash |
|---|
| 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 |
|---|
| # 定义删除天数
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 |
|---|
| 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))秒)"
|
结果输出展示
统计脚本执行时间,可以方便find查找时间差