实战案例:服务器磁盘空间告急,如何快速定位和清理"大文件"

1. 问题背景与解决思路

当服务器磁盘空间告急时,系统性能会急剧下降,甚至可能导致服务不可用。本教程将详细介绍如何快速定位占用磁盘空间的大文件,并进行安全清理。

1.1 整体解决流程

graph TB A[磁盘空间告急] --> B[检查磁盘使用情况] B --> C[定位大文件目录] C --> D[分析文件类型和大小] D --> E[安全清理策略] E --> F[验证清理效果] F --> G[建立监控预防] style A fill:#ff6b6b,stroke:#fff,stroke-width:2px,color:#fff style B fill:#4ecdc4,stroke:#fff,stroke-width:2px,color:#fff style C fill:#45b7d1,stroke:#fff,stroke-width:2px,color:#fff style D fill:#96ceb4,stroke:#fff,stroke-width:2px,color:#fff style E fill:#feca57,stroke:#fff,stroke-width:2px,color:#fff style F fill:#ff9ff3,stroke:#fff,stroke-width:2px,color:#fff style G fill:#54a0ff,stroke:#fff,stroke-width:2px,color:#fff classDef default fill:#333,stroke:#fff,stroke-width:2px,color:#fff;

2. 环境准备和基础检查

2.1 创建检查脚本文件

文件名: disk_cleanup_helper.sh

bash 复制代码
#!/bin/bash

# 磁盘清理助手脚本
# 功能:自动化磁盘空间检查和清理

set -e  # 遇到错误立即退出

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

# 检查是否以root用户运行
check_root() {
    if [[ $EUID -eq 0 ]]; then
        log_info "以root用户运行"
    else
        log_warn "建议使用root用户运行以获得完整权限"
    fi
}

# 主函数
main() {
    log_info "开始磁盘空间检查"
    check_root
    
    echo "=================================================="
    echo "           磁盘清理助手 v1.0"
    echo "=================================================="
    echo "1. 检查磁盘使用情况"
    echo "2. 查找大文件"
    echo "3. 查找大目录"
    echo "4. 清理临时文件"
    echo "5. 清理日志文件"
    echo "6. 退出"
    echo "=================================================="
    
    read -p "请选择操作 [1-6]: " choice
    
    case $choice in
        1) check_disk_usage ;;
        2) find_large_files ;;
        3) find_large_directories ;;
        4) cleanup_temp_files ;;
        5) cleanup_log_files ;;
        6) exit 0 ;;
        *) log_error "无效选择" && main ;;
    esac
}

# 后续函数定义将在这里添加

3. 磁盘使用情况检查

3.1 检查磁盘使用情况函数

将以下函数添加到 disk_cleanup_helper.sh 中:

bash 复制代码
# 检查磁盘使用情况
check_disk_usage() {
    log_info "开始检查磁盘使用情况..."
    
    echo -e "\n${YELLOW}=== 磁盘空间使用情况 ===${NC}"
    df -h | grep -v tmpfs
    
    echo -e "\n${YELLOW}=== inode使用情况 ===${NC}"
    df -i | grep -v tmpfs
    
    echo -e "\n${YELLOW}=== 根目录使用情况详情 ===${NC}"
    du -sh /* 2>/dev/null | sort -hr | head -20
    
    # 检查磁盘使用率超过80%的分区
    local high_usage=$(df -h | awk '0+$5 >= 80 {print $1 " : " $5}')
    if [[ -n "$high_usage" ]]; then
        log_warn "以下分区使用率超过80%:"
        echo "$high_usage"
    else
        log_success "所有分区使用率正常"
    fi
    
    read -p "按回车键继续..."
    main
}

3.2 创建专门的磁盘检查脚本

文件名: disk_analyzer.sh

bash 复制代码
#!/bin/bash

# 磁盘分析脚本 - 详细分析磁盘使用情况

# 颜色设置
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'

# 阈值设置
DISK_WARNING=80
DISK_CRITICAL=90
LARGE_FILE_SIZE="500M"  # 大文件阈值

# 生成报告
generate_report() {
    local report_file="/tmp/disk_analysis_report_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "磁盘分析报告 - 生成时间: $(date)" > $report_file
    echo "==========================================" >> $report_file
    
    # 磁盘使用情况
    echo -e "\n1. 磁盘空间使用情况:" >> $report_file
    df -h >> $report_file
    
    # 大文件查找
    echo -e "\n2. 根目录下大于${LARGE_FILE_SIZE}的文件:" >> $report_file
    find / -type f -size +${LARGE_FILE_SIZE} 2>/dev/null | xargs du -h 2>/dev/null | sort -hr >> $report_file
    
    # 目录大小
    echo -e "\n3. 根目录下各目录大小:" >> $report_file
    du -sh /* 2>/dev/null | sort -hr >> $report_file
    
    echo -e "\n报告已保存至: $report_file"
    echo -e "使用命令查看: ${YELLOW}less $report_file${NC}"
}

# 详细磁盘检查
detailed_disk_check() {
    echo -e "${CYAN}=== 详细磁盘分析 ===${NC}"
    
    # 1. 基本磁盘信息
    echo -e "\n${YELLOW}1. 磁盘分区信息:${NC}"
    lsblk
    
    # 2. 挂载点详细信息
    echo -e "\n${YELLOW}2. 挂载点详细信息:${NC}"
    mount | grep -E "^/dev"
    
    # 3. 检查磁盘健康(如果有smartctl)
    if command -v smartctl &> /dev/null; then
        echo -e "\n${YELLOW}3. 磁盘健康检查:${NC}"
        for disk in $(lsblk -d -o NAME | grep -v NAME); do
            if [[ -e "/dev/$disk" ]]; then
                echo "检查 /dev/$disk ..."
                smartctl -H "/dev/$disk" 2>/dev/null | grep -E "(SMART|result)" || true
            fi
        done
    fi
    
    # 4. 生成详细报告
    generate_report
}

# 监控模式
monitor_mode() {
    echo -e "${GREEN}启动磁盘监控模式,每60秒刷新一次...${NC}"
    echo -e "按 Ctrl+C 退出监控\n"
    
    while true; do
        clear
        echo -e "${CYAN}=== 磁盘监控 - $(date) ===${NC}"
        echo -e "${YELLOW}磁盘使用情况:${NC}"
        df -h | grep -v tmpfs
        
        # 高亮显示使用率高的分区
        echo -e "\n${YELLOW}警告级别:${NC}"
        df -h | awk -v warn=$DISK_WARNING -v crit=$DISK_CRITICAL '
            NR>1 {
                usage = substr($5, 1, length($5)-1)
                if (usage >= crit) 
                    printf "'${RED}'CRITICAL: %s 使用率 %s'${NC}'\n", $1, $5
                else if (usage >= warn) 
                    printf "'${YELLOW}'WARNING: %s 使用率 %s'${NC}'\n", $1, $5
            }'
        
        sleep 60
    done
}

main() {
    echo -e "${PURPLE}================================${NC}"
    echo -e "${PURPLE}       磁盘分析工具 v1.0       ${NC}"
    echo -e "${PURPLE}================================${NC}"
    echo "1. 快速磁盘检查"
    echo "2. 详细磁盘分析"
    echo "3. 实时监控模式"
    echo "4. 生成分析报告"
    echo "5. 退出"
    echo -e "${PURPLE}================================${NC}"
    
    read -p "请选择操作 [1-5]: " choice
    
    case $choice in
        1) 
            echo -e "${CYAN}=== 快速磁盘检查 ===${NC}"
            df -h
            ;;
        2) detailed_disk_check ;;
        3) monitor_mode ;;
        4) generate_report ;;
        5) exit 0 ;;
        *) echo -e "${RED}无效选择${NC}" && main ;;
    esac
    
    read -p "按回车键返回主菜单..."
    main
}

# 脚本入口
if [[ "$1" == "monitor" ]]; then
    monitor_mode
else
    main
fi

4. 定位大文件和大目录

4.1 大文件查找函数

将以下函数添加到 disk_cleanup_helper.sh 中:

bash 复制代码
# 查找大文件
find_large_files() {
    log_info "开始查找大文件..."
    
    local size_threshold="100M"
    read -p "设置文件大小阈值 (默认: 100M): " custom_size
    if [[ -n "$custom_size" ]]; then
        size_threshold=$custom_size
    fi
    
    echo -e "\n${YELLOW}=== 查找大于 ${size_threshold} 的文件 ===${NC}"
    
    # 创建临时文件保存结果
    local temp_file=$(mktemp)
    
    log_info "正在扫描,这可能需要几分钟..."
    
    # 查找大文件并排序
    find / -type f -size +${size_threshold} 2>/dev/null | \
    xargs du -h 2>/dev/null | \
    sort -hr > "$temp_file"
    
    if [[ -s "$temp_file" ]]; then
        echo -e "\n${GREEN}找到的大文件列表:${NC}"
        head -50 "$temp_file" | awk '{printf "%-10s %s\n", $1, $2}'
        
        local total_count=$(wc -l < "$temp_file")
        echo -e "\n${BLUE}总共找到 ${total_count} 个大于 ${size_threshold} 的文件${NC}"
        
        # 保存完整结果
        local result_file="/tmp/large_files_$(date +%Y%m%d_%H%M%S).txt"
        cp "$temp_file" "$result_file"
        log_info "完整结果已保存至: $result_file"
    else
        log_warn "未找到大于 ${size_threshold} 的文件"
    fi
    
    # 清理临时文件
    rm -f "$temp_file"
    
    read -p "按回车键继续..."
    main
}

# 查找大目录
find_large_directories() {
    log_info "开始查找大目录..."
    
    local depth=3
    read -p "设置扫描深度 (默认: 3): " custom_depth
    if [[ -n "$custom_depth" ]]; then
        depth=$custom_depth
    fi
    
    echo -e "\n${YELLOW}=== 查找前20个大目录 (深度: ${depth}) ===${NC}"
    
    # 扫描指定深度的目录
    for i in $(seq 1 $depth); do
        echo -e "\n${CYAN}=== 深度 $i ===${NC}"
        du -h --max-depth=$i / 2>/dev/null | sort -hr | head -20
    done
    
    # 详细扫描home目录
    echo -e "\n${YELLOW}=== /home 目录详细分析 ===${NC}"
    if [[ -d "/home" ]]; then
        du -sh /home/* 2>/dev/null | sort -hr | head -10
    fi
    
    # 详细扫描var目录
    echo -e "\n${YELLOW}=== /var 目录详细分析 ===${NC}"
    if [[ -d "/var" ]]; then
        du -sh /var/* 2>/dev/null | sort -hr | head -10
    fi
    
    read -p "按回车键继续..."
    main
}

4.2 创建高级文件分析工具

文件名: file_analyzer.sh

bash 复制代码
#!/bin/bash

# 高级文件分析工具

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'

# 文件类型分析
analyze_file_types() {
    local target_dir="${1:-/}"
    local depth="${2:-2}"
    
    echo -e "${CYAN}分析目录: $target_dir (深度: $depth)${NC}"
    
    # 按文件类型统计
    echo -e "\n${YELLOW}=== 按文件类型统计 ===${NC}"
    find "$target_dir" -maxdepth $depth -type f 2>/dev/null | \
    awk -F. '{
        if (NF>1) { 
            ext = tolower($NF)
            if (length(ext) < 10) types[ext]++
        } else {
            types["no_extension"]++
        }
        total++
    } 
    END {
        for (ext in types) {
            printf "%-15s: %8d files (%5.1f%%)\n", ext, types[ext], (types[ext]/total)*100
        }
        printf "%-15s: %8d files\n", "TOTAL", total
    }' | sort -k2 -nr
    
    # 按文件大小区间统计
    echo -e "\n${YELLOW}=== 按文件大小区间统计 ===${NC}"
    find "$target_dir" -maxdepth $depth -type f 2>/dev/null | \
    xargs du -k 2>/dev/null | \
    awk '
    {
        size = $1
        if (size < 100) small++
        else if (size < 1024) medium++      # < 1MB
        else if (size < 10240) large++      # < 10MB
        else if (size < 102400) very_large++ # < 100MB
        else huge++
        total_files++
    }
    END {
        printf "%-15s: %8d files (%5.1f%%)\n", "< 100KB", small, (small/total_files)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "100KB-1MB", medium, (medium/total_files)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "1MB-10MB", large, (large/total_files)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "10MB-100MB", very_large, (very_large/total_files)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "> 100MB", huge, (huge/total_files)*100
        printf "%-15s: %8d files\n", "TOTAL", total_files
    }'
}

# 查找重复文件
find_duplicate_files() {
    local target_dir="${1:-/}"
    
    echo -e "${CYAN}查找重复文件: $target_dir${NC}"
    echo -e "${YELLOW}这可能需要较长时间...${NC}"
    
    find "$target_dir" -type f 2>/dev/null | \
    xargs md5sum 2>/dev/null | \
    sort | \
    uniq -w32 -d --all-repeated=separate | \
    awk '{
        if ($1 != prev_md5) {
            if (count > 1) {
                printf "\n%s - %d duplicates\n", prev_md5, count
                for (i=0; i<count; i++) printf "  %s\n", files[i]
            }
            count = 0
            prev_md5 = $1
        }
        files[count] = $2
        count++
    }
    END {
        if (count > 1) {
            printf "\n%s - %d duplicates\n", prev_md5, count
            for (i=0; i<count; i++) printf "  %s\n", files[i]
        }
    }'
}

# 文件时间分析
analyze_file_ages() {
    local target_dir="${1:-/}"
    
    echo -e "${CYAN}分析文件修改时间: $target_dir${NC}"
    
    find "$target_dir" -type f 2>/dev/null | \
    xargs stat -c %Y 2>/dev/null | \
    awk -v now=$(date +%s) '
    {
        age = now - $1
        if (age < 86400) today++           # < 1天
        else if (age < 604800) week++      # < 1周
        else if (age < 2592000) month++    # < 1月
        else if (age < 31536000) year++    # < 1年
        else old++                         # > 1年
        total++
    }
    END {
        printf "%-15s: %8d files (%5.1f%%)\n", "< 1天", today, (today/total)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "1天-1周", week, (week/total)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "1周-1月", month, (month/total)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "1月-1年", year, (year/total)*100
        printf "%-15s: %8d files (%5.1f%%)\n", "> 1年", old, (old/total)*100
        printf "%-15s: %8d files\n", "TOTAL", total
    }'
}

# 大文件详细分析
detailed_large_file_analysis() {
    local min_size="${1:-100M}"
    
    echo -e "${CYAN}详细大文件分析 (大于 $min_size)${NC}"
    
    # 查找并分析大文件
    find / -type f -size +$min_size 2>/dev/null | \
    while read file; do
        if [[ -f "$file" ]]; then
            size=$(du -h "$file" 2>/dev/null | cut -f1)
            mtime=$(stat -c %y "$file" 2>/dev/null | cut -d' ' -f1)
            file_type=$(file -b "$file" 2>/dev/null | cut -c1-50)
            owner=$(stat -c %U "$file" 2>/dev/null)
            
            printf "%-10s %-12s %-15s %-50s %s\n" \
                   "$size" "$mtime" "$owner" "${file_type:-unknown}" "$file"
        fi
    done | sort -hr | head -30
}

main() {
    echo -e "${PURPLE}================================${NC}"
    echo -e "${PURPLE}       高级文件分析工具        ${NC}"
    echo -e "${PURPLE}================================${NC}"
    echo "1. 文件类型分析"
    echo "2. 查找重复文件"
    echo "3. 文件时间分析"
    echo "4. 大文件详细分析"
    echo "5. 退出"
    echo -e "${PURPLE}================================${NC}"
    
    read -p "请选择操作 [1-5]: " choice
    
    case $choice in
        1) 
            read -p "请输入要分析的目录 (默认: /): " dir
            analyze_file_types "${dir:-/}" 
            ;;
        2) 
            read -p "请输入要查找的目录 (默认: /): " dir
            find_duplicate_files "${dir:-/}"
            ;;
        3) 
            read -p "请输入要分析的目录 (默认: /): " dir
            analyze_file_ages "${dir:-/}"
            ;;
        4) 
            read -p "请输入最小文件大小 (默认: 100M): " size
            detailed_large_file_analysis "${size:-100M}"
            ;;
        5) exit 0 ;;
        *) echo -e "${RED}无效选择${NC}" && main ;;
    esac
    
    read -p "按回车键返回主菜单..."
    main
}

main

5. 安全清理操作

5.1 临时文件清理函数

将以下函数添加到 disk_cleanup_helper.sh 中:

bash 复制代码
# 清理临时文件
cleanup_temp_files() {
    log_info "开始清理临时文件..."
    
    local total_before=$(df / | awk 'NR==2 {print $4}')
    
    echo -e "${YELLOW}=== 清理系统临时文件 ===${NC}"
    
    # 清理 /tmp 目录
    if [[ -d "/tmp" ]]; then
        local tmp_size=$(du -sh /tmp 2>/dev/null | cut -f1)
        log_info "清理 /tmp 目录 (当前大小: ${tmp_size})"
        find /tmp -type f -atime +7 -delete 2>/dev/null || true
    fi
    
    # 清理缓存文件
    echo -e "\n${YELLOW}=== 清理缓存文件 ===${NC}"
    # 安全清理yum缓存
    if command -v yum &> /dev/null; then
        log_info "清理 yum 缓存"
        yum clean all 2>/dev/null || true
    fi
    
    # 清理apt缓存
    if command -v apt-get &> /dev/null; then
        log_info "清理 apt 缓存"
        apt-get clean 2>/dev/null || true
    fi
    
    # 清理pip缓存
    if command -v pip &> /dev/null; then
        log_info "清理 pip 缓存"
        pip cache purge 2>/dev/null || true
    fi
    
    # 清理日志轮转文件
    echo -e "\n${YELLOW}=== 清理旧日志文件 ===${NC}"
    find /var/log -name "*.log.*" -type f -mtime +30 -delete 2>/dev/null || true
    find /var/log -name "*.gz" -type f -mtime +30 -delete 2>/dev/null || true
    
    # 清理系统缓存(需要root权限)
    if [[ $EUID -eq 0 ]]; then
        echo -e "\n${YELLOW}=== 清理系统缓存 ===${NC}"
        sync
        echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true
    fi
    
    local total_after=$(df / | awk 'NR==2 {print $4}')
    local freed_space=$((total_after - total_before))
    
    if [[ $freed_space -gt 0 ]]; then
        log_success "清理完成,释放空间: ${freed_space}KB"
    else
        log_info "清理完成,但未释放额外空间"
    fi
    
    read -p "按回车键继续..."
    main
}

# 清理日志文件
cleanup_log_files() {
    log_info "开始清理日志文件..."
    
    echo -e "${YELLOW}=== 日志文件分析 ===${NC}"
    
    # 检查日志目录大小
    if [[ -d "/var/log" ]]; then
        local log_size=$(du -sh /var/log 2>/dev/null | cut -f1)
        echo -e "当前 /var/log 目录大小: ${RED}${log_size}${NC}"
    fi
    
    # 显示大日志文件
    echo -e "\n${YELLOW}=== 大日志文件列表 ===${NC}"
    find /var/log -type f -name "*.log" -size +100M 2>/dev/null | \
    xargs du -h 2>/dev/null | sort -hr | head -10
    
    # 安全清理选项
    echo -e "\n${CYAN}=== 安全清理选项 ===${NC}"
    echo "1. 清空特定日志文件(保留文件)"
    echo "2. 删除旧日志文件(30天前)"
    echo "3. 压缩旧日志文件"
    echo "4. 返回主菜单"
    
    read -p "请选择操作 [1-4]: " log_choice
    
    case $log_choice in
        1)
            read -p "请输入要清空的日志文件路径: " log_file
            if [[ -f "$log_file" && -w "$log_file" ]]; then
                log_info "清空日志文件: $log_file"
                : > "$log_file"
                log_success "日志文件已清空"
            else
                log_error "无法访问或写入文件: $log_file"
            fi
            ;;
        2)
            log_info "删除30天前的日志文件"
            find /var/log -name "*.log.*" -type f -mtime +30 -delete 2>/dev/null
            find /var/log -name "*.gz" -type f -mtime +30 -delete 2>/dev/null
            log_success "旧日志文件已删除"
            ;;
        3)
            log_info "压缩7天前的日志文件"
            find /var/log -name "*.log" -type f -mtime +7 -exec gzip {} \; 2>/dev/null
            log_success "日志文件已压缩"
            ;;
        4)
            main
            return
            ;;
        *)
            log_error "无效选择"
            ;;
    esac
    
    # 显示清理后的大小
    if [[ -d "/var/log" ]]; then
        local new_log_size=$(du -sh /var/log 2>/dev/null | cut -f1)
        echo -e "\n清理后 /var/log 目录大小: ${GREEN}${new_log_size}${NC}"
    fi
    
    read -p "按回车键继续..."
    main
}

5.2 创建安全清理脚本

文件名: safe_cleanup.sh

bash 复制代码
#!/bin/bash

# 安全清理脚本 - 提供安全的文件清理功能

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'

# 备份目录
BACKUP_DIR="/tmp/cleanup_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# 日志函数
log() {
    echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$BACKUP_DIR/cleanup.log"
}

warn() {
    echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$BACKUP_DIR/cleanup.log"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1" | tee -a "$BACKUP_DIR/cleanup.log"
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$BACKUP_DIR/cleanup.log"
}

# 创建备份
backup_file() {
    local file="$1"
    local reason="$2"
    
    if [[ -e "$file" ]]; then
        local backup_path="$BACKUP_DIR/$(echo "$file" | tr '/' '_')"
        log "备份文件: $file -> $backup_path (原因: $reason)"
        cp -r "$file" "$backup_path" 2>/dev/null || true
    fi
}

# 交互式删除
interactive_delete() {
    local target="$1"
    local reason="$2"
    
    if [[ ! -e "$target" ]]; then
        warn "文件不存在: $target"
        return
    fi
    
    local size=$(du -sh "$target" 2>/dev/null | cut -f1)
    
    echo -e "\n${YELLOW}=== 删除确认 ===${NC}"
    echo "文件: $target"
    echo "大小: $size"
    echo "原因: $reason"
    echo -e "${RED}此操作不可逆!${NC}"
    
    read -p "确认删除?(y/N): " confirm
    if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
        backup_file "$target" "$reason"
        if rm -rf "$target"; then
            success "已删除: $target (释放空间: $size)"
        else
            error "删除失败: $target"
        fi
    else
        log "取消删除: $target"
    fi
}

# 清理Docker相关文件
cleanup_docker() {
    if ! command -v docker &> /dev/null; then
        log "Docker 未安装,跳过清理"
        return
    fi
    
    echo -e "\n${CYAN}=== Docker 清理 ===${NC}"
    
    # 检查Docker磁盘使用
    local docker_size=$(docker system df 2>/dev/null | grep -v "RECLAIMABLE" | awk 'NR>1 {print $1}' | head -1)
    log "Docker 当前使用: $docker_size"
    
    echo -e "\n${YELLOW}Docker 清理选项:${NC}"
    echo "1. 清理所有停止的容器"
    echo "2. 清理所有未使用的镜像"
    echo "3. 清理所有未使用的网络"
    echo "4. 清理构建缓存"
    echo "5. 全部清理"
    
    read -p "请选择 [1-5]: " docker_choice
    
    case $docker_choice in
        1) docker container prune -f ;;
        2) docker image prune -a -f ;;
        3) docker network prune -f ;;
        4) docker builder prune -f ;;
        5) docker system prune -a -f ;;
        *) log "跳过 Docker 清理" ;;
    esac
    
    local new_docker_size=$(docker system df 2>/dev/null | grep -v "RECLAIMABLE" | awk 'NR>1 {print $1}' | head -1)
    success "Docker 清理完成,当前使用: $new_docker_size"
}

# 清理软件包缓存
cleanup_package_cache() {
    echo -e "\n${CYAN}=== 软件包缓存清理 ===${NC}"
    
    if command -v apt-get &> /dev/null; then
        log "清理 APT 缓存"
        local apt_before=$(du -sh /var/cache/apt 2>/dev/null | cut -f1)
        apt-get autoremove -y
        apt-get autoclean
        apt-get clean
        local apt_after=$(du -sh /var/cache/apt 2>/dev/null | cut -f1)
        success "APT 缓存清理完成: $apt_before -> $apt_after"
    fi
    
    if command -v yum &> /dev/null; then
        log "清理 YUM 缓存"
        local yum_before=$(du -sh /var/cache/yum 2>/dev/null | cut -f1)
        yum clean all
        local yum_after=$(du -sh /var/cache/yum 2>/dev/null | cut -f1)
        success "YUM 缓存清理完成: $yum_before -> $yum_after"
    fi
}

# 清理用户缓存
cleanup_user_cache() {
    echo -e "\n${CYAN}=== 用户缓存清理 ===${NC}"
    
    # 清理浏览器缓存(如果有)
    for user_home in /home/*; do
        if [[ -d "$user_home" ]]; then
            local user=$(basename "$user_home")
            log "清理用户 $user 的缓存"
            
            # Chrome缓存
            local chrome_cache="$user_home/.cache/google-chrome"
            if [[ -d "$chrome_cache" ]]; then
                local chrome_size=$(du -sh "$chrome_cache" 2>/dev/null | cut -f1)
                rm -rf "$chrome_cache"/Default/Cache/*
                success "清理 Chrome 缓存: 释放 $chrome_size"
            fi
            
            # 通用缓存
            local cache_dir="$user_home/.cache"
            if [[ -d "$cache_dir" ]]; then
                find "$cache_dir" -type f -atime +30 -delete 2>/dev/null || true
            fi
        fi
    done
}

# 核心文件保护检查
check_protected_files() {
    local file="$1"
    
    # 系统关键文件保护
    local protected_patterns=(
        "/bin/" "/sbin/" "/usr/bin/" "/usr/sbin/"
        "/lib/" "/lib64/" "/usr/lib/" "/usr/lib64/"
        "/etc/passwd" "/etc/shadow" "/etc/group"
        "/boot/" "/root/" "/home/"
    )
    
    for pattern in "${protected_patterns[@]}"; do
        if [[ "$file" == "$pattern"* ]]; then
            return 0  # 受保护文件
        fi
    done
    
    return 1  # 非保护文件
}

# 主清理函数
main_cleanup() {
    log "开始安全清理操作"
    log "备份目录: $BACKUP_DIR"
    
    # 显示当前磁盘空间
    echo -e "\n${CYAN}=== 当前磁盘空间 ===${NC}"
    df -h /
    
    # 执行各种清理
    cleanup_package_cache
    cleanup_docker
    cleanup_user_cache
    
    # 清理系统临时文件
    echo -e "\n${CYAN}=== 系统临时文件清理 ===${NC}"
    find /tmp -type f -atime +7 -delete 2>/dev/null || true
    find /var/tmp -type f -atime +30 -delete 2>/dev/null || true
    
    # 清理旧日志
    echo -e "\n${CYAN}=== 旧日志文件清理 ===${NC}"
    find /var/log -name "*.log.*" -type f -mtime +30 -delete 2>/dev/null || true
    find /var/log -name "*.gz" -type f -mtime +30 -delete 2>/dev/null || true
    
    # 显示清理结果
    echo -e "\n${GREEN}=== 清理完成 ===${NC}"
    df -h /
    
    log "清理操作完成"
    log "备份文件保存在: $BACKUP_DIR"
    echo -e "${YELLOW}重要: 请检查备份目录确认无误后,可手动删除备份文件${NC}"
}

# 脚本入口
if [[ "$1" == "--auto" ]]; then
    main_cleanup
else
    echo -e "${PURPLE}=== 安全清理脚本 ===${NC}"
    echo "此脚本将执行安全的磁盘清理操作"
    echo "所有删除的文件都会备份到: $BACKUP_DIR"
    echo -e "${YELLOW}建议先备份重要数据!${NC}"
    
    read -p "是否继续?(y/N): " confirm
    if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
        main_cleanup
    else
        echo "操作已取消"
        exit 0
    fi
fi

6. 自动化监控和预防

6.1 创建磁盘监控脚本

文件名: disk_monitor.sh

bash 复制代码
#!/bin/bash

# 磁盘监控和自动清理脚本

set -e

# 配置
CONFIG_FILE="/etc/disk_monitor.conf"
LOG_FILE="/var/log/disk_monitor.log"
ALERT_THRESHOLD=80
CRITICAL_THRESHOLD=90
CHECK_INTERVAL=300  # 5分钟

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 日志函数
log() {
    echo -e "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
    echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1"
}

# 发送告警
send_alert() {
    local partition="$1"
    local usage="$2"
    local level="$3"
    local message="磁盘告警: 分区 $partition 使用率 ${usage}% (${level})"
    
    log "$message"
    
    # 尝试发送邮件告警(如果有邮件配置)
    if command -v mail &> /dev/null; then
        echo "$message" | mail -s "磁盘空间告警 - $(hostname)" root
    fi
    
    # 写入系统日志
    logger "磁盘监控: $message"
}

# 检查磁盘使用率
check_disk_usage() {
    df -h | awk 'NR>1 {print $1 "," $5 "," $6}' | while IFS=',' read -r device usage mount; do
        # 移除百分比符号
        usage=${usage%\%}
        
        # 跳过特定文件系统
        if [[ "$mount" == "/boot" ]] || [[ "$device" == tmpfs* ]] || [[ "$device" == devtmpfs* ]]; then
            continue
        fi
        
        if [[ "$usage" -ge "$CRITICAL_THRESHOLD" ]]; then
            send_alert "$device" "$usage" "CRITICAL"
            emergency_cleanup "$mount"
        elif [[ "$usage" -ge "$ALERT_THRESHOLD" ]]; then
            send_alert "$device" "$usage" "WARNING"
            auto_cleanup "$mount"
        fi
    done
}

# 自动清理
auto_cleanup() {
    local mount_point="$1"
    log "执行自动清理: $mount_point"
    
    # 清理临时文件
    find "$mount_point/tmp" -type f -atime +1 -delete 2>/dev/null || true
    
    # 清理缓存
    if [[ -d "$mount_point/var/cache" ]]; then
        find "$mount_point/var/cache" -type f -atime +7 -delete 2>/dev/null || true
    fi
    
    # 清理日志文件(保留最近7天)
    if [[ -d "$mount_point/var/log" ]]; then
        find "$mount_point/var/log" -name "*.log.*" -type f -mtime +7 -delete 2>/dev/null || true
    fi
}

# 紧急清理
emergency_cleanup() {
    local mount_point="$1"
    log "执行紧急清理: $mount_point"
    
    # 更激进的清理策略
    auto_cleanup "$mount_point"
    
    # 清理Docker(如果使用)
    if command -v docker &> /dev/null; then
        docker system prune -a -f 2>/dev/null || true
    fi
    
    # 清理软件包缓存
    if command -v apt-get &> /dev/null; then
        apt-get clean 2>/dev/null || true
    fi
    
    if command -v yum &> /dev/null; then
        yum clean all 2>/dev/null || true
    fi
}

# 生成报告
generate_report() {
    local report_file="/tmp/disk_report_$(date +%Y%m%d).txt"
    
    echo "磁盘监控报告 - $(date)" > "$report_file"
    echo "==========================================" >> "$report_file"
    
    # 磁盘使用情况
    echo -e "\n磁盘使用情况:" >> "$report_file"
    df -h >> "$report_file"
    
    # 大文件列表
    echo -e "\n前20个大文件:" >> "$report_file"
    find / -type f -size +100M 2>/dev/null | xargs du -h 2>/dev/null | sort -hr | head -20 >> "$report_file"
    
    # 目录大小
    echo -e "\n目录大小统计:" >> "$report_file"
    du -sh /* 2>/dev/null | sort -hr >> "$report_file"
    
    log "报告已生成: $report_file"
}

# 监控模式
monitor_mode() {
    log "启动磁盘监控模式 (检查间隔: ${CHECK_INTERVAL}秒)"
    log "告警阈值: ${ALERT_THRESHOLD}%, 紧急阈值: ${CRITICAL_THRESHOLD}%"
    
    while true; do
        check_disk_usage
        sleep "$CHECK_INTERVAL"
    done
}

# 安装服务
install_service() {
    if [[ $EUID -ne 0 ]]; then
        echo -e "${RED}需要root权限安装服务${NC}"
        exit 1
    fi
    
    local service_file="/etc/systemd/system/disk-monitor.service"
    
    cat > "$service_file" << EOF
[Unit]
Description=Disk Space Monitor
After=network.target

[Service]
Type=simple
ExecStart=$PWD/disk_monitor.sh --daemon
Restart=always
RestartSec=60
User=root

[Install]
WantedBy=multi-user.target
EOF
    
    systemctl daemon-reload
    systemctl enable disk-monitor.service
    
    echo -e "${GREEN}服务安装完成${NC}"
    echo "启动服务: systemctl start disk-monitor"
    echo "查看状态: systemctl status disk-monitor"
}

# 显示帮助
show_help() {
    echo "磁盘监控脚本"
    echo
    echo "用法: $0 [选项]"
    echo
    echo "选项:"
    echo "  --monitor    启动监控模式"
    echo "  --report     生成磁盘报告"
    echo "  --install    安装为系统服务"
    echo "  --daemon     守护进程模式(内部使用)"
    echo "  --help       显示此帮助信息"
}

# 主函数
main() {
    case "$1" in
        --monitor)
            monitor_mode
            ;;
        --report)
            generate_report
            ;;
        --install)
            install_service
            ;;
        --daemon)
            # 守护进程模式
            exec > /dev/null 2>&1
            monitor_mode
            ;;
        --help)
            show_help
            ;;
        *)
            echo -e "${GREEN}磁盘监控脚本${NC}"
            echo "请使用 --help 查看可用选项"
            ;;
    esac
}

# 脚本入口
if [[ $# -eq 0 ]]; then
    show_help
else
    main "$1"
fi

6.2 创建配置文件

文件名: disk_monitor.conf

bash 复制代码
# 磁盘监控配置文件

# 监控设置
ALERT_THRESHOLD=80
CRITICAL_THRESHOLD=90
CHECK_INTERVAL=300

# 排除的文件系统(逗号分隔)
EXCLUDE_FILESYSTEMS="tmpfs,devtmpfs,overlay"

# 排除的挂载点(逗号分隔)
EXCLUDE_MOUNTS="/boot,/proc,/sys"

# 清理设置
CLEANUP_TEMP_DAYS=1
CLEANUP_CACHE_DAYS=7
CLEANUP_LOG_DAYS=7

# 邮件告警设置
MAIL_ENABLED=true
MAIL_RECIPIENTS="admin@company.com"
MAIL_SUBJECT_PREFIX="[Disk Alert]"

# 日志设置
LOG_LEVEL="INFO"  # DEBUG, INFO, WARN, ERROR
LOG_RETENTION_DAYS=30

# 自动清理设置
AUTO_CLEANUP_ENABLED=true
EMERGENCY_CLEANUP_ENABLED=true

# 监控的分区(为空则监控所有分区)
# MONITOR_PARTITIONS="/,/home,/var"

# 大文件阈值(用于报告)
LARGE_FILE_THRESHOLD="100M"

7. 完整的使用流程

7.1 执行步骤

graph TD A[开始磁盘清理] --> B[运行基础检查] B --> C[分析磁盘使用情况] C --> D{是否发现大文件?} D -->|是| E[定位具体大文件] D -->|否| F[检查其他问题] E --> G[分析文件安全性] G --> H[执行安全清理] H --> I[验证清理效果] I --> J[建立监控预防] F --> J J --> K[完成] style A fill:#ff6b6b,stroke:#fff,stroke-width:2px,color:#fff style B fill:#4ecdc4,stroke:#fff,stroke-width:2px,color:#fff style C fill:#45b7d1,stroke:#fff,stroke-width:2px,color:#fff style E fill:#feca57,stroke:#fff,stroke-width:2px,color:#fff style H fill:#ff9ff3,stroke:#fff,stroke-width:2px,color:#fff style J fill:#54a0ff,stroke:#fff,stroke-width:2px,color:#fff style K fill:#1dd1a1,stroke:#fff,stroke-width:2px,color:#fff classDef default fill:#333,stroke:#fff,stroke-width:2px,color:#fff;

7.2 使用示例

第一步:赋予执行权限并运行基础检查

bash 复制代码
# 赋予所有脚本执行权限
chmod +x disk_cleanup_helper.sh disk_analyzer.sh file_analyzer.sh safe_cleanup.sh disk_monitor.sh

# 运行基础检查
./disk_cleanup_helper.sh

第二步:使用详细分析工具

bash 复制代码
# 运行磁盘分析
./disk_analyzer.sh

# 运行文件分析
./file_analyzer.sh

第三步:执行安全清理

bash 复制代码
# 交互式安全清理
./safe_cleanup.sh

# 或者自动清理
./safe_cleanup.sh --auto

第四步:设置监控

bash 复制代码
# 安装监控服务(需要root)
sudo ./disk_monitor.sh --install

# 或者直接运行监控
./disk_monitor.sh --monitor

8. 总结

本教程提供了完整的服务器磁盘空间清理解决方案,包括:

  1. 基础检查工具 - 快速了解磁盘使用情况
  2. 详细分析工具 - 深入分析文件和目录
  3. 安全清理工具 - 避免误删重要文件
  4. 自动监控系统 - 预防磁盘空间问题

所有脚本都设计为可以直接使用,适合零基础用户按照步骤操作。建议在生产环境使用前,先在测试环境验证,确保理解每个步骤的影响。

通过这套工具,您可以快速定位磁盘空间问题,安全地清理不必要的文件,并建立长期的监控机制,确保服务器稳定运行。

相关推荐
LCG元2 小时前
Linux 性能监控三板斧:top/vmstat/iostat 快速入门
linux
以琦琦为中心2 小时前
很好!从 `fdisk -l` 输出可以看到您的磁盘确实是600GB,但只有29.5GB被分配给根分区 `/dev/sda3`。现在我来帮您扩展这个分区。
linux·ubuntu
wc_xue_fei_le2 小时前
11.11DNS主从服务器
linux·服务器·前端
用户31187945592182 小时前
申威SW64系统安装docker-ce-19.03.14.rpm详细教程(附安装包)
linux
white-persist2 小时前
二进制movl及CTF逆向GDB解析:Python(env)环境下dbg从原理到实战
linux·服务器·开发语言·python·网络安全·信息可视化·系统安全
Le_ee2 小时前
Rocky Linux 8 网络配置
linux·运维·服务器
CS_浮鱼3 小时前
【Linux】基础IO
linux·运维·chrome
序属秋秋秋3 小时前
《Linux系统编程之进程基础》【进程状态】
linux·运维·c语言·c++·笔记·操作系统·进程状态
BS_Li3 小时前
【Linux系统编程】进程控制
java·linux·数据库