如何写一个脚本定时清理缓存

wen 实用脚本 4

从零到自动化的完整指南

目录导读

  1. 为什么要清理缓存? – 缓存堆积的隐患与收益分析
  2. 脚本编写前必知 – 选择合适的语言与系统环境
  3. 核心代码实现 – 以Shell与Python为例的清理逻辑
  4. 定时任务配置 – crontab与任务调度器的实战设置
  5. 安全与优化 – 避免误删、记录日志与告警机制
  6. 常见问答 – 针对高频问题的深度解答

为什么要清理缓存?

缓存是计算机系统中提高访问速度的“双刃剑”,以Linux系统为例,/tmp目录、应用日志、DNS缓存、软件包管理器缓存(如apt-get/var/cache/apt)会随时间膨胀,一次生产环境事故让我记忆犹新:某台Web服务器因Nginx代理缓存文件未及时清理,磁盘占用率飙升至95%,导致页面响应延迟30秒以上,定期清理缓存可带来三大收益:

如何写一个脚本定时清理缓存

  • 释放磁盘空间:尤其是日志轮转后的残留文件,每月可回收数GB。
  • 提升系统稳定性:避免inode耗尽导致的“磁盘空间充足却无法写入”的假死状态。
  • 保护隐私与安全:如浏览器缓存中的敏感临时文件,定时清理可降低泄露风险。

但盲目清理同样危险——若删除了运行中的进程锁文件或数据库临时表,可能引发服务崩溃,脚本必须设计“白名单保护”机制。


脚本编写前必知

1 选择语言

  • Shell脚本(Bash):适合Linux/Unix环境,直接调用系统命令,轻量高效,推荐用于清理/tmp、日志文件等基础场景。
  • Python脚本:具备异常处理、跨平台兼容性(Windows也可用osshutil模块),适合复杂的清理逻辑,如根据文件年龄、大小、类型过滤。
  • PowerShell:Windows环境首选,可清理IIS缓存、用户临时文件夹等。

2 确定清理目标

列出需要清理的路径清单, | 路径 | 清理规则 | 风险等级 | |------|----------|----------| | /tmp/* | 删除24小时以上文件 | 低(需排除运行中的.sock文件) | | /var/log/*.log | 保留最近7天日志 | 低(日志轮转工具配合) | | ~/.cache/ | 保留最近30天 | 中(应用可能重建缓存) | | C:\Windows\Temp | 删除超过1小时文件 | 高(需避开正在使用的临时文件) |


核心代码实现

1 Shell脚本示例(Linux通用)

#!/bin/bash
# 脚本名:clean_cache.sh
# 功能:清理系统临时文件与日志,排除关键路径
# 定义需要清理的目录
CACHE_DIRS=(
    "/tmp"
    "/var/tmp"
    "/var/log"  # 仅处理日志文件,不删目录本身
    "/root/.cache"
)
# 保护列表:绝对不能删除的文件或目录模式(支持通配符)
PROTECTED_PATTERNS=(
    "/tmp/*.sock"        # 避免删除进程间通信套接字
    "/var/log/wtmp"      # 系统登录记录文件
    "/var/log/btmp"      # 错误登录记录
)
# 清理函数:删除超过3天的文件,但跳过保护模式
clean_dir() {
    local dir=$1
    local pattern=$2
    if [ -d "$dir" ]; then
        # 使用find遍历,-mtime +3表示修改时间超过3天
        find "$dir" -type f -mtime +3 ! -name "$pattern" -exec rm -f {} \; 2>/dev/null
        # 删除空目录(非保护路径)
        find "$dir" -type d -empty -delete 2>/dev/null
    fi
}
# 主逻辑
for dir in "${CACHE_DIRS[@]}"; do
    clean_dir "$dir" "*"
done
# 针对特定保护模式做额外排除
for pattern in "${PROTECTED_PATTERNS[@]}"; do
    # 提取模式所在的父目录,重新保护
    parent_dir=$(dirname "$pattern")
    file_name=$(basename "$pattern")
    if [ -f "$parent_dir/$file_name" ]; then
        touch -t 197001010000 "$parent_dir/$file_name"  # 强制将修改时间改为1970年,避免被清理
    fi
done
echo "清理完成: $(date)"

关键点说明

  • 2>/dev/null隐藏权限错误(无需每次写入系统日志)。
  • 保护列表通过touch命令将文件的mtime改为1970年,确保find -mtime +3找不到它。
  • 空目录删除使用-empty -delete,避免残留无意义的文件夹。

2 Python脚本示例(跨平台)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""跨平台缓存清理脚本(支持Windows与Linux)"""
import os
import sys
import time
import shutil
from pathlib import Path
# 配置清理规则:[路径, 文件最小年龄(秒), 是否递归, 排除后缀]
CLEAN_RULES = [
    (Path.home() / ".cache", 86400 * 30, True, [".lock"]),        # 保留30天,排除锁文件
    (Path("/tmp"), 3600 * 24, True, [".sock", ".pid"]),          # 24小时,排除套接字与pid文件
    (Path("/var/log"), 86400 * 7, True, [".gz"]),                # 7天,排除压缩日志(由logrotate管理)
    (Path("C:\\Windows\\Temp"), 3600, True, [".tmp"])             # Windows临时目录,1小时,排除正在使用的.tmp
]
def should_keep(file_path, exclude_extensions):
    """判断文件是否应该被保留"""
    # 排除正在被使用的文件(通过检查是否被进程锁定,此处简单判断扩展名)
    for ext in exclude_extensions:
        if file_path.suffix == ext:
            return True
    # 排除Windows正在写入的文件(模拟检测:尝试以独占方式打开文件,失败则保留)
    try:
        with open(file_path, 'rb') as f:
            f.read(1)
    except PermissionError:
        return True
    return False
def clean_cache():
    for base_path, max_age, recursive, exts in CLEAN_RULES:
        if not base_path.exists():
            continue
        current_time = time.time()
        if recursive:
            for file_path in base_path.rglob('*'):
                if file_path.is_file() and not should_keep(file_path, exts):
                    file_age = current_time - file_path.stat().st_mtime
                    if file_age > max_age:
                        try:
                            file_path.unlink(missing_ok=True)
                            print(f"Deleted: {file_path}")
                        except OSError as e:
                            print(f"Failed to delete {file_path}: {e}", file=sys.stderr)
        else:
            for file_path in base_path.iterdir():
                if file_path.is_file() and not should_keep(file_path, exts):
                    file_age = current_time - file_path.stat().st_mtime
                    if file_age > max_age:
                        try:
                            file_path.unlink(missing_ok=True)
                        except OSError:
                            pass
if __name__ == "__main__":
    clean_cache()
    print(f"缓存清理执行完毕: {time.ctime()}")

Python优势

  • 通过Path.home()自动获取当前用户目录,兼容Linux与Windows。
  • should_keep函数包含文件锁定检测(Python的PermissionError可捕获Windows独占锁)。
  • 支持自定义排除扩展名(如.lock.pid),避免误删关键文件。

定时任务配置

1 Linux Crontab配置

执行crontab -e,添加以下任务(每天凌晨3点执行清理脚本):

0 3 * * * /usr/bin/bash /opt/scripts/clean_cache.sh >> /var/log/clean_cache.log 2>&1

参数解析

  • 0 3 * * * 表示每天03:00执行。
  • >> 将标准输出追加到日志文件,2>&1 将错误输出也重定向到日志。
  • 建议日志路径使用绝对路径,避免相对路径问题。

2 Windows任务计划程序

  1. 打开“任务计划程序”,创建基本任务。
  2. 设置触发器:每天、每周或指定时间。
  3. 操作:启动程序 → 浏览选择python.exe(或直接选your_script.py),参数输入脚本路径。
  4. 勾选“不管用户是否登录都要运行”,确保服务器重启后仍生效。

3 高级技巧:日志轮转

定期任务生成的日志可能也需清理,在脚本开头添加日志文件大小检测:

# 如果日志文件超过10MB,则压缩并删除旧内容
if [ -f /var/log/clean_cache.log ] && [ $(stat -c%s /var/log/clean_cache.log) -gt 10485760 ]; then
    gzip -f /var/log/clean_cache.log
    touch /var/log/clean_cache.log
fi

安全与优化

1 使用“试运行”模式

在脚本中添加一个--dry-run参数,仅输出将要删除的文件而不实际操作:

import sys
dry_run = '--dry-run' in sys.argv
if dry_run:
    print(f"[试运行] 将要删除: {file_path}")
else:
    file_path.unlink()

2 告警机制

若清理后磁盘空间仍不足,发送邮件或推送通知:

import subprocess
def send_alert(msg):
    subprocess.run(["mail", "-s", "清理告警", "admin@example.com"], input=msg, text=True)
# 在清理函数末尾检查磁盘
disk_usage = shutil.disk_usage("/")
if disk_usage.free / disk_usage.total < 0.1:  # 剩余空间低于10%
    send_alert(f"清理后磁盘使用率仍超过90%,当前剩余: {disk_usage.free // 2**30}GB")

3 避免误删的终极策略

  • 白名单优先:明确声明“绝不删除.py、.sh、.conf、.db”等文件。
  • 版本控制:对核心服务器的清理脚本,先提交到Git仓库,变更需审核。
  • 权限分离:运行脚本的用户不应拥有root权限,仅对目标目录有读写权限。

常见问答

Q1:清理缓存时,如何避免删除正在被使用的文件?

A

  • Linux下,可通过lsof命令检查文件是否被占用:lsof /tmp/deleted_file
  • Windows下,Python使用PermissionError捕获独占锁(如上述脚本所示)。
  • 更稳妥的做法是:先使用fuser -k(Linux)杀死占用进程,或直接跳过这类文件。

Q2:脚本定时任务执行后,日志显示“Permission denied”怎么办?

A

  • 检查脚本执行权限:chmod +x clean_cache.sh
  • 确认目标目录的访问权限:对于/var/log等系统目录,需要root用户运行脚本(可通过sudo crontab -e以root身份设置任务)。
  • 也可以在脚本中使用sudo,但不推荐——更好的做法是给运行用户添加sudoers规则,允许无密码执行特定命令。

Q3:如何检查缓存清理的效果?

A

  • 在脚本中添加统计功能:记录清理前后磁盘使用率df -h /
  • 使用du -sh /var/cache/对比。
  • 最关键的是观察应用日志是否恢复正常(如Nginx错误日志中不再出现“No space left on device”)。

Q4:Windows下是否有类似crontab的原生工具?

A:有,除了“任务计划程序”,还可使用PowerShell的Register-ScheduledJob(需管理员权限),示例:

$trigger = New-JobTrigger -Daily -At "03:00AM"
Register-ScheduledJob -Name "CleanCacheTask" -FilePath "C:\scripts\clean_cache.ps1" -Trigger $trigger

注意:PowerShell脚本执行需先启用Set-ExecutionPolicy RemoteSigned

Q5:缓存清理脚本多久执行一次最合适?

A:没有标准答案,取决于缓存增长率。

  • 高频场景(如Web服务器Nginx代理缓存):建议每小时清理一次(条件:仅清理超过24小时的文件)。
  • 低频场景(如用户浏览器缓存):每天清理30天前的即可。
  • 极端场景(如监控系统日志):每6小时检查一次,保留最近3天的日志。

编写一个可靠的定时清理缓存脚本,本质上是“在自动化与安全之间找平衡”,本文提供的Shell与Python双实现、crontab与任务计划器配置、保护机制与告警策略,能覆盖90%以上的实际需求,永远先用--dry-run测试,再将清理阈值设定得保守一些——每天删除一成长1GB的文件,比一周清空10GB再等系统奔溃要明智得多,从最小化权限、白名单保护、日志审计三个维度出发,你的缓存清理脚本将从“危险工具”变为“系统管家”。

抱歉,评论功能暂时关闭!