如何写临时目录自动清理脚本

wen 实用脚本 29

从入门到生产级实践指南

目录导读

  1. 为什么需要临时目录自动清理?
  2. 清理脚本的核心逻辑与设计原则
  3. 多平台清理脚本实战(Linux/Windows/macOS)
  4. 高级特性:日志、安全与定时任务
  5. 常见错误与优化问答
  6. 生产环境部署建议

为什么需要临时目录自动清理? {#why}

许多开发者和运维人员都遇到过这样的场景:服务器磁盘空间被/tmp目录下的临时文件占满,导致应用崩溃;或者电脑桌面的“临时下载”文件夹里堆积了成百上千个无用文件。据统计,超过40%的磁盘空间浪费来源于未及时清理的临时文件

如何写临时目录自动清理脚本

核心痛点

  • 手动清理耗时且易遗忘
  • 某些临时文件可能被进程锁定,误删导致程序异常
  • 不同操作系统临时目录路径各异(Linux为/tmp,Windows为%TEMP%,macOS为/private/tmp

问:为什么不能用系统自带的清理工具?
答:系统工具(如Linux的tmpwatch)通常只能按最后访问时间删除,无法自定义文件类型或命名模式;且部分生产环境需保留特定临时文件(如进程锁文件),自定义脚本可以解决这些精细化管理需求。


清理脚本的核心逻辑与设计原则 {#core}

一个优秀的自动清理脚本应遵循以下四原则

1 安全第一原则

  • 白名单保护:永远不要删除正在被进程引用的文件(通过lsofhandle检测)
  • 干跑模式(Dry-run):先模拟执行,输出将要删除的文件列表,确认无误后再真正运行

2 时间阈值管理

  • 按“最后访问时间”(atime)或“最后修改时间”(mtime)判断
  • 设置合理的保留周期:日志类文件可保留7天,编译中间件保留1天

3 递归与排除规则

  • 只清理指定目录(避免误删系统关键目录)
  • 支持排除特定子目录或文件通配符(如*.log除外)

4 幂等性与可恢复性

  • 脚本执行后不改变系统状态(除删除外)
  • 记录删除日志,便于回溯恢复

多平台清理脚本实战 {#practice}

1 Linux/macOS 通用Shell脚本

#!/bin/bash
# temp_cleaner.sh - 临时目录自动清理脚本
# 使用方法: bash temp_cleaner.sh [--dry-run] [--days 7]
TEMP_DIRS=("/tmp" "/var/tmp" "$HOME/.cache")
DAYS=7
DRY_RUN=false
# 参数解析
while [[ "$#" -gt 0 ]]; do
    case $1 in
        --dry-run) DRY_RUN=true ;;
        --days) DAYS="$2"; shift ;;
        *) echo "未知参数: $1"; exit 1 ;;
    esac
    shift
done
# 核心清理函数
clean_temp() {
    local dir=$1
    local days=$2
    local dry_run=$3
    if [ ! -d "$dir" ]; then
        echo "警告: 目录 $dir 不存在,跳过"
        return
    fi
    # 排除被进程锁定的文件
    find "$dir" -type f -atime +"$days" | while read -r file; do
        if lsof -l "$file" 2>/dev/null | grep -q .; then
            echo "跳过正在使用的文件: $file"
        else
            if [ "$dry_run" = true ]; then
                echo "[模拟] 将删除: $file"
            else
                rm -f "$file"
                echo "已删除: $file"
            fi
        fi
    done
}
# 执行清理
for dir in "${TEMP_DIRS[@]}"; do
    echo "正在清理: $dir"
    clean_temp "$dir" "$DAYS" "$DRY_RUN"
done

关键点

  • 使用lsof检测文件是否被占用,避免误删
  • --dry-run参数允许用户验证操作

2 Windows PowerShell脚本

# temp_cleaner.ps1
param(
    [switch]$DryRun,
    [int]$DaysOld = 7,
    [string[]]$TempPaths = @("$env:TEMP", "$env:WINDIR\Temp")
)
function Clean-Temp {
    param($Path, $Days, $DryRun)
    if (-not (Test-Path $Path)) { return }
    Get-ChildItem -Path $Path -Recurse -Force | Where-Object {
        $_.LastAccessTime -lt (Get-Date).AddDays(-$Days)
    } | ForEach-Object {
        if ($DryRun) {
            Write-Host "[模拟] 将删除: $($_.FullName)"
        } else {
            try {
                Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
                Write-Host "已删除: $($_.FullName)"
            } catch {
                Write-Warning "无法删除: $($_.FullName) - $($_.Exception.Message)"
            }
        }
    }
}
# 执行
foreach ($path in $TempPaths) {
    Write-Host "正在清理: $path"
    Clean-Temp -Path $path -Days $DaysOld -DryRun $DryRun
}

Windows注意事项

  • 部分临时文件可能被系统服务锁定(如CBS日志),需添加-ErrorAction SilentlyContinue避免脚本中断
  • 使用LastAccessTime而非LastWriteTime更符合临时文件清理逻辑

高级特性:日志、安全与定时任务 {#advanced}

1 日志记录与审计

在脚本中添加日志功能:

LOG_FILE="/var/log/temp_cleaner_$(date +%Y%m%d).log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "=== 清理开始于 $(date) ==="
# ... 清理逻辑 ...
echo "=== 清理结束于 $(date) ==="

2 安全增强措施

  • 元数据备份:删除前将文件列表写入/var/log/deleted_files.csv
  • 软链接检测:避免删除指向系统文件的符号链接
  • 配额限制:单次清理不超过总空间的20%,防止IO风暴

3 定时任务设置

Linux(crontab)

# 每天凌晨3点执行,保留7天文件
0 3 * * * /usr/local/bin/temp_cleaner.sh --days 7 >> /var/log/temp_cleaner_cron.log 2>&1

Windows(任务计划程序)

  • 创建基本任务:触发器设为每天,操作选择powershell.exe -File "C:\Scripts\temp_cleaner.ps1"

macOS(launchd): 创建plist文件~/Library/LaunchAgents/com.cleaner.temp.plist

<key>StartCalendarInterval</key>
<dict>
    <key>Hour</key><integer>3</integer>
    <key>Minute</key><integer>0</integer>
</dict>
<key>ProgramArguments</key>
<array>
    <string>/usr/local/bin/temp_cleaner.sh</string>
    <string>--days</string><string>7</string>
</array>

常见错误与优化问答 {#faq}

Q1:清理后系统变慢怎么办?
A:不要在业务高峰期执行(如数据库备份时段),添加IO限速:ionice -c 2 -n 7 find ...

Q2:macOS的/tmp是软链怎么办?
A:默认/tmp指向/private/tmp,脚本应处理软链目标而不是软链本身,用readlink -f解析真实路径

Q3:如何清理Docker容器内的临时文件?
A:容器内单独部署脚本或使用docker system prune -a(注意会清理全部未使用对象)

Q4:rm -rf误删了重要文件怎么办?
A:最佳实践是先用--dry-run验证,并开启系统回收站(如Linux的trash-cli)。
替代方案:将文件移动到回收站而不是删除:

TRASH="$HOME/.trash"
mkdir -p "$TRASH"
mv "$file" "$TRASH/$(date +%Y%m%d_%H%M%S)_$filename"

生产环境部署建议 {#deployment}

  1. 灰度发布:先在测试环境运行一周,确认没有误删后再上线
  2. 告警集成:当清理量超过50GB时,通过Webhook通知运维群
  3. 多级清理策略
    • 高速缓存(如编译产物):保留2天
    • 日志文件:保留15天
    • 用户临时下载:保留7天
  4. 定期检查:每月手动对比实际文件与脚本策略是否匹配

最终核心理念:临时目录清理不是“一键删除”,而是基于安全策略的有序管理系统,通过本文提供的多平台脚本框架和最佳实践,你可以定制出既安全又高效的自动化方案。

(注:文中涉及的lsof、find等命令的详细用法,请查阅各系统的man手册获取原始权威说明)

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