介绍

这个脚本是使用人工智能创建的,专门用于管理Linux系统虚拟内存的,因为前几天我彻底弃用宝塔面板,然后然而ACE面板并没有相应的虚拟内存管理工具,所以就只能依赖于脚本关闭了,毕竟手动关闭太麻烦了。然后我就使用通义千问生成脚本,终于在第四版达到了生产级。然后就是一些感慨,一年过去了,人工智能确实在变强,至少我见到的Github上Web项目的脚本的维护真的已经可以完全交给人工智能了。

脚本

#!/bin/bash

# =============================================================================
# 虚拟内存(Swap)管理脚本 v4 (生产级)
# =============================================================================
# 功能: 创建/删除/管理Linux系统swap空间
# 作者: 通义千问
# 版本: 4.0.0
# 日期: 2026-02-18
# =============================================================================
# 使用方法: sudo ./swap_manager.sh [命令] [参数]
# 示例:     sudo ./swap_manager.sh on 4G
# =============================================================================

set -o pipefail

# -----------------------------------------------------------------------------
# 配置常量
# -----------------------------------------------------------------------------
SCRIPT_NAME=$(basename "$0")
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SWAP_FILE="/swapfile"
LOG_FILE="/var/log/swap_manager.log"
FSTAB_BACKUP_DIR="/var/backup/swap_manager"
MAX_SWAP_WAIT_SECONDS=60
MIN_DISK_FREE_PERCENT=15

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

# -----------------------------------------------------------------------------
# 日志函数
# -----------------------------------------------------------------------------
init_log() {
    mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
    touch "$LOG_FILE" 2>/dev/null || LOG_FILE="/tmp/swap_manager.log"
}

log() {
    local level="$1"
    local message="$2"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] [$level] $message" >> "$LOG_FILE" 2>/dev/null
}

log_info() { log "INFO" "$1"; }
log_warn() { log "WARN" "$1"; }
log_error() { log "ERROR" "$1"; }

# -----------------------------------------------------------------------------
# 初始化检查
# -----------------------------------------------------------------------------
init_check() {
    init_log
    log_info "========== 脚本启动 =========="
    log_info "命令: $*"
    
    # 检查root权限
    if [ "$EUID" -ne 0 ]; then
        echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}"
        echo "用法: sudo $SCRIPT_NAME [on|off|status|delete|swappiness|restore|help] [参数]"
        log_error "非root用户尝试运行"
        exit 1
    fi
    
    # 检查必要命令
    local required_commands="swapon swapoff mkswap free df sed awk grep chmod chown"
    for cmd in $required_commands; do
        if ! command -v "$cmd" &> /dev/null; then
            echo -e "${RED}错误: 缺少必要命令 '$cmd'${NC}"
            log_error "缺少必要命令: $cmd"
            exit 1
        fi
    done
    
    # 创建备份目录
    mkdir -p "$FSTAB_BACKUP_DIR" 2>/dev/null
    
    log_info "初始化检查完成"
}

# -----------------------------------------------------------------------------
# 显示swap状态
# -----------------------------------------------------------------------------
show_status() {
    echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║     当前虚拟内存(Swap)状态             ║${NC}"
    echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
    echo ""
    
    # Swap设备列表
    echo -e "${CYAN}┌─ Swap设备列表 ─────────────────────────┐${NC}"
    if swapon --show &>/dev/null; then
        local swap_count=$(swapon --show --noheadings 2>/dev/null | wc -l)
        if [ "$swap_count" -gt 0 ]; then
            swapon --show --bytes 2>/dev/null | while read -r line; do
                echo -e "  ${GREEN}✓${NC} $line"
            done
        else
            echo -e "  ${YELLOW}无活动的swap设备${NC}"
        fi
    else
        echo -e "  ${RED}无法获取swap信息${NC}"
    fi
    echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
    echo ""
    
    # 内存使用情况
    echo -e "${CYAN}┌─ 内存使用情况 ─────────────────────────┐${NC}"
    if command -v free &>/dev/null; then
        free -h 2>/dev/null | grep -i swap | while read -r line; do
            echo "  $line"
        done
        
        # 计算使用率
        local swap_total=$(free | awk '/Swap/ {print $2}')
        local swap_used=$(free | awk '/Swap/ {print $3}')
        if [ "$swap_total" -gt 0 ] 2>/dev/null; then
            local swap_percent=$((swap_used * 100 / swap_total))
            echo ""
            echo -e "  Swap使用率: ${YELLOW}${swap_percent}%${NC}"
        fi
    else
        echo -e "  ${RED}free命令不可用${NC}"
    fi
    echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
    echo ""
    
    # Swappiness值
    echo -e "${CYAN}┌─ Swappiness配置 ───────────────────────┐${NC}"
    if [ -f /proc/sys/vm/swappiness ]; then
        local swappiness=$(cat /proc/sys/vm/swappiness 2>/dev/null)
        echo -e "  当前值: ${YELLOW}${swappiness}${NC}"
        echo -e "  说明: 0=避免swap, 60=默认, 100=积极使用"
    else
        echo -e "  ${RED}无法读取swappiness值${NC}"
    fi
    echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
    echo ""
    
    # Swap文件信息
    echo -e "${CYAN}┌─ Swap文件信息 ─────────────────────────┐${NC}"
    if [ -f "$SWAP_FILE" ]; then
        local swap_size=$(ls -lh "$SWAP_FILE" 2>/dev/null | awk '{print $5}')
        local swap_perms=$(ls -l "$SWAP_FILE" 2>/dev/null | awk '{print $1}')
        local swap_owner=$(ls -l "$SWAP_FILE" 2>/dev/null | awk '{print $3":"$4}')
        local swap_attr=$(lsattr "$SWAP_FILE" 2>/dev/null | awk '{print $1}')
        echo -e "  路径: ${GREEN}$SWAP_FILE${NC}"
        echo -e "  大小: $swap_size"
        echo -e "  权限: $swap_perms"
        echo -e "  所有者: $swap_owner"
        echo -e "  属性: ${swap_attr:-无特殊属性}"
    else
        echo -e "  ${YELLOW}Swap文件不存在${NC}"
    fi
    echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
    echo ""
    
    # Fstab配置
    echo -e "${CYAN}┌─ /etc/fstab配置 ───────────────────────┐${NC}"
    if [ -f /etc/fstab ]; then
        local fstab_swap=$(grep -E 'swap|swapfile' /etc/fstab 2>/dev/null)
        if [ -n "$fstab_swap" ]; then
            echo "$fstab_swap" | while read -r line; do
                echo -e "  ${GREEN}$line${NC}"
            done
        else
            echo -e "  ${YELLOW}无swap相关配置${NC}"
        fi
    else
        echo -e "  ${RED}/etc/fstab不存在${NC}"
    fi
    echo -e "${CYAN}└────────────────────────────────────────┘${NC}"
    echo ""
    
    log_info "状态检查完成"
}

# -----------------------------------------------------------------------------
# 验证大小格式
# -----------------------------------------------------------------------------
validate_size() {
    local size="$1"
    if [[ ! $size =~ ^[0-9]+[KkMmGg][Bb]?$ ]]; then
        echo -e "${RED}错误: 无效的大小格式 '${size}'${NC}"
        echo "请使用格式: 数字+单位 (如 2G, 4G, 512M, 1GB)"
        log_error "无效的大小格式: $size"
        exit 1
    fi
}

# -----------------------------------------------------------------------------
# 转换大小为字节
# -----------------------------------------------------------------------------
size_to_bytes() {
    local size="$1"
    local num=$(echo "$size" | sed 's/[^0-9]//g')
    local unit=$(echo "$size" | sed 's/[0-9]//g' | tr '[:lower:]' '[:upper:]' | sed 's/B$//')
    
    case "$unit" in
        G) echo $((num * 1024 * 1024 * 1024)) ;;
        M) echo $((num * 1024 * 1024)) ;;
        K) echo $((num * 1024)) ;;
        *) echo $((num * 1024 * 1024 * 1024)) ;; # 默认GB
    esac
}

# -----------------------------------------------------------------------------
# 检查文件系统类型
# -----------------------------------------------------------------------------
check_filesystem() {
    local target_path="$1"
    local fs_type=$(df -T "$target_path" 2>/dev/null | awk 'NR==2 {print $2}')
    
    log_info "文件系统类型: $fs_type"
    
    # 不支持的文件系统
    local unsupported_fs="nfs cifs smbfs fuse.sshfs tmpfs ramfs"
    for fs in $unsupported_fs; do
        if [ "$fs_type" = "$fs" ] || [[ "$fs_type" == *"$fs"* ]]; then
            echo -e "${RED}错误: 不支持在 '$fs_type' 文件系统上创建swap${NC}"
            echo "Swap文件需要本地磁盘文件系统 (ext4, xfs, btrfs等)"
            log_error "不支持的文件系统: $fs_type"
            exit 1
        fi
    done
    
    # 警告某些文件系统
    if [ "$fs_type" = "btrfs" ]; then
        echo -e "${YELLOW}警告: Btrfs文件系统可能需要特殊配置${NC}"
        echo "建议: 使用 nodatacow 选项或考虑使用swap分区"
    fi
    
    echo "$fs_type"
}

# -----------------------------------------------------------------------------
# 检查磁盘空间
# -----------------------------------------------------------------------------
check_disk_space() {
    local required_bytes="$1"
    local mount_point="/"
    
    # 获取可用空间(字节)
    local available_bytes=$(df -B1 "$mount_point" 2>/dev/null | awk 'NR==2 {print $4}')
    
    if [ -z "$available_bytes" ] || [ "$available_bytes" -eq 0 ]; then
        echo -e "${RED}错误: 无法获取磁盘空间信息${NC}"
        log_error "无法获取磁盘空间"
        exit 1
    fi
    
    # 计算可用百分比
    local total_bytes=$(df -B1 "$mount_point" 2>/dev/null | awk 'NR==2 {print $2}')
    local free_percent=$((available_bytes * 100 / total_bytes))
    
    # 检查最小可用空间
    if [ "$free_percent" -lt "$MIN_DISK_FREE_PERCENT" ]; then
        echo -e "${RED}错误: 磁盘可用空间不足 (${free_percent}%)${NC}"
        echo "建议至少保留 ${MIN_DISK_FREE_PERCENT}% 的可用空间"
        log_error "磁盘空间不足: ${free_percent}%"
        exit 1
    fi
    
    # 检查是否足够创建swap(预留10%缓冲)
    local required_with_buffer=$((required_bytes * 110 / 100))
    if [ "$available_bytes" -lt "$required_with_buffer" ]; then
        local available_gb=$((available_bytes / 1024 / 1024 / 1024))
        local required_gb=$((required_with_buffer / 1024 / 1024 / 1024 + 1))
        echo -e "${RED}错误: 磁盘空间不足${NC}"
        echo "  可用空间: ${available_gb}G"
        echo "  需要空间: ${required_gb}G (含10%缓冲)"
        log_error "空间不足: 可用${available_bytes}字节, 需要${required_with_buffer}字节"
        exit 1
    fi
    
    log_info "磁盘空间检查通过: 可用${available_bytes}字节, 需要${required_bytes}字节"
    return 0
}

# -----------------------------------------------------------------------------
# 检查现有swap
# -----------------------------------------------------------------------------
check_existing_swap() {
    local existing_count=$(swapon --show --noheadings 2>/dev/null | wc -l)
    
    if [ "$existing_count" -gt 0 ]; then
        echo -e "${YELLOW}注意: 系统已有 $existing_count 个swap设备${NC}"
        swapon --show 2>/dev/null | while read -r line; do
            echo -e "  $line"
        done
        log_info "现有swap设备数: $existing_count"
    else
        log_info "无现有swap设备"
    fi
    
    return 0
}

# -----------------------------------------------------------------------------
# 等待swap关闭完成
# -----------------------------------------------------------------------------
wait_for_swapoff() {
    local target_file="$1"
    local max_wait="$MAX_SWAP_WAIT_SECONDS"
    local waited=0
    
    echo -e "${YELLOW}等待swap完全关闭...${NC}"
    
    while [ $waited -lt $max_wait ]; do
        if ! swapon --show 2>/dev/null | grep -q "$target_file"; then
            log_info "swap在 ${waited}秒后成功关闭"
            return 0
        fi
        sleep 1
        waited=$((waited + 1))
        
        # 每10秒显示进度
        if [ $((waited % 10)) -eq 0 ]; then
            echo -e "  已等待 ${waited}/${max_wait} 秒..."
        fi
    done
    
    log_warn "等待swap关闭超时 (${max_wait}秒)"
    return 1
}

# -----------------------------------------------------------------------------
# 备份fstab
# -----------------------------------------------------------------------------
backup_fstab() {
    if [ ! -f /etc/fstab ]; then
        log_warn "/etc/fstab不存在,跳过备份"
        return 0
    fi
    
    local backup_file="${FSTAB_BACKUP_DIR}/fstab.backup.$(date +%Y%m%d_%H%M%S)"
    if cp /etc/fstab "$backup_file" 2>/dev/null; then
        echo -e "${GREEN}✓ 已备份 /etc/fstab 到 $backup_file${NC}"
        log_info "fstab备份完成: $backup_file"
        return 0
    else
        echo -e "${RED}✗ 备份 /etc/fstab 失败${NC}"
        log_error "fstab备份失败"
        return 1
    fi
}

# -----------------------------------------------------------------------------
# 从备份恢复fstab
# -----------------------------------------------------------------------------
restore_fstab() {
    echo -e "${CYAN}可用的fstab备份:${NC}"
    local backups=$(ls -t "${FSTAB_BACKUP_DIR}"/fstab.backup.* 2>/dev/null)
    
    if [ -z "$backups" ]; then
        echo -e "${RED}未找到任何备份文件${NC}"
        return 1
    fi
    
    echo "$backups" | head -10 | nl
    echo ""
    
    read -p "选择要恢复的备份编号 (1-10, 或按回车取消): " choice
    
    if [ -z "$choice" ]; then
        echo "操作已取消"
        return 0
    fi
    
    local selected=$(echo "$backups" | head -10 | sed -n "${choice}p")
    
    if [ -z "$selected" ]; then
        echo -e "${RED}无效的选择${NC}"
        return 1
    fi
    
    echo -e "${YELLOW}将恢复: $selected${NC}"
    read -p "确认恢复?(y/n): " confirm
    confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
    
    if [ "$confirm" = "y" ]; then
        if cp "$selected" /etc/fstab 2>/dev/null; then
            echo -e "${GREEN}✓ fstab已恢复${NC}"
            log_info "fstab已从 $selected 恢复"
            return 0
        else
            echo -e "${RED}✗ 恢复失败${NC}"
            log_error "fstab恢复失败"
            return 1
        fi
    else
        echo "操作已取消"
        return 0
    fi
}

# -----------------------------------------------------------------------------
# 关闭swap
# -----------------------------------------------------------------------------
swap_off() {
    echo -e "${YELLOW}正在关闭虚拟内存(swap)...${NC}"
    log_info "开始关闭swap"
    
    # 检查当前swap使用情况
    local swap_total=$(free | awk '/Swap/ {print $2}')
    local swap_used=$(free | awk '/Swap/ {print $3}')
    
    if [ "$swap_total" -gt 0 ] 2>/dev/null && [ "$swap_used" -gt 0 ] 2>/dev/null; then
        local swap_percent=$((swap_used * 100 / swap_total))
        echo -e "${YELLOW}当前swap使用率: ${swap_percent}% (${swap_used}KB / ${swap_total}KB)${NC}"
        
        if [ "$swap_percent" -gt 80 ]; then
            echo -e "${RED}警告: swap使用率过高${NC}"
            echo -e "${YELLOW}建议先关闭占用swap的程序${NC}"
            echo -e "${CYAN}尝试清理页面缓存...${NC}"
            sync
            echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
            sleep 2
        fi
        
        echo ""
        read -p "是否继续?(y/n): " confirm
        confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
        if [ "$confirm" != "y" ]; then
            echo "操作已取消"
            log_info "用户取消关闭swap"
            return 0
        fi
    fi
    
    # 关闭所有swap
    echo -e "${CYAN}执行 swapoff -a...${NC}"
    swapoff -a 2>/dev/null
    local swapoff_result=$?
    
    if [ $swapoff_result -eq 0 ]; then
        # 等待并验证
        if wait_for_swapoff "$SWAP_FILE"; then
            echo -e "${GREEN}✓ 虚拟内存已成功关闭${NC}"
            log_info "swap关闭成功"
        else
            echo -e "${YELLOW}⚠ swapoff完成但检测到swap仍活动${NC}"
            log_warn "swap关闭后仍有活动swap"
        fi
    else
        echo -e "${YELLOW}swapoff -a 失败,尝试单独关闭...${NC}"
        swapoff "$SWAP_FILE" 2>/dev/null
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}✓ 虚拟内存已成功关闭${NC}"
            log_info "swap单独关闭成功"
        else
            echo -e "${RED}✗ 关闭虚拟内存失败${NC}"
            echo -e "${CYAN}当前活动的swap设备:${NC}"
            swapon --show 2>/dev/null
            log_error "swap关闭失败"
            return 1
        fi
    fi
    
    echo ""
    show_status
    return 0
}

# -----------------------------------------------------------------------------
# 开启swap
# -----------------------------------------------------------------------------
swap_on() {
    local swap_size="$1"
    log_info "开始开启swap, 大小: ${swap_size:-现有}"
    
    echo -e "${YELLOW}正在开启虚拟内存(swap)...${NC}"
    echo ""
    
    # 检查现有swap
    check_existing_swap
    
    # 如果指定了大小,创建新的swap文件
    if [ -n "$swap_size" ]; then
        echo -e "${CYAN}将创建 ${swap_size} 的swap文件${NC}"
        
        # 检查文件系统
        check_filesystem "/"
        echo ""
        
        # 检查磁盘空间
        local required_bytes=$(size_to_bytes "$swap_size")
        check_disk_space "$required_bytes"
        echo ""
        
        # 检查swap文件是否已存在
        if [ -f "$SWAP_FILE" ]; then
            echo -e "${YELLOW}警告: $SWAP_FILE 已存在${NC}"
            read -p "是否删除并重新创建?(y/n): " confirm
            confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
            if [ "$confirm" = "y" ]; then
                echo -e "${CYAN}关闭现有swap...${NC}"
                swapoff "$SWAP_FILE" 2>/dev/null
                rm -f "$SWAP_FILE"
                echo -e "${GREEN}✓ 已删除旧swap文件${NC}"
                log_info "删除旧swap文件"
            else
                echo "操作已取消"
                log_info "用户取消创建swap"
                return 0
            fi
        fi
        
        # 创建swap文件
        echo -e "${CYAN}正在创建swap文件,请稍候...${NC}"
        log_info "开始创建swap文件: $swap_size"
        
        # 尝试fallocate
        fallocate -l "$swap_size" "$SWAP_FILE" 2>/dev/null
        local fallocate_result=$?
        
        if [ $fallocate_result -ne 0 ] || [ ! -f "$SWAP_FILE" ] || [ ! -s "$SWAP_FILE" ]; then
            echo -e "${YELLOW}fallocate不可用或失败,使用dd方法...${NC}"
            log_info "fallocate失败,使用dd"
            
            local num=$(echo "$swap_size" | sed 's/[^0-9]//g')
            local unit=$(echo "$swap_size" | sed 's/[0-9]//g' | tr '[:lower:]' '[:upper:]' | sed 's/B$//')
            local bs=1024
            local count
            
            case "$unit" in
                G) count=$((num * 1024 * 1024)) ;;
                M) count=$((num * 1024)) ;;
                K) count=$num ;;
                *) count=$((num * 1024 * 1024)) ;;
            esac
            
            dd if=/dev/zero of="$SWAP_FILE" bs=$bs count=$count status=progress 2>&1 | tail -5
        fi
        
        # 验证文件创建
        if [ ! -f "$SWAP_FILE" ]; then
            echo -e "${RED}✗ Swap文件创建失败${NC}"
            log_error "swap文件创建失败"
            return 1
        fi
        
        # 设置权限和所有者
        chmod 600 "$SWAP_FILE"
        chown root:root "$SWAP_FILE"
        echo -e "${GREEN}✓ Swap文件创建完成${NC}"
        log_info "swap文件创建完成: $(ls -lh $SWAP_FILE)"
        
        # 格式化为swap
        echo -e "${CYAN}正在格式化swap...${NC}"
        mkswap "$SWAP_FILE" 2>&1 | tail -3
        if [ $? -ne 0 ]; then
            echo -e "${RED}✗ swap格式化失败${NC}"
            log_error "swap格式化失败"
            rm -f "$SWAP_FILE"
            return 1
        fi
        echo -e "${GREEN}✓ Swap格式化完成${NC}"
    else
        # 使用现有swap文件
        if [ ! -f "$SWAP_FILE" ]; then
            echo -e "${RED}错误: $SWAP_FILE 不存在${NC}"
            echo "请先使用 'sudo $SCRIPT_NAME on [大小]' 创建swap文件"
            log_error "swap文件不存在"
            return 1
        fi
        echo -e "${CYAN}使用现有swap文件: $SWAP_FILE${NC}"
    fi
    
    # 启用swap
    echo -e "${CYAN}正在启用swap...${NC}"
    swapon "$SWAP_FILE" 2>/dev/null
    local swapon_result=$?
    
    if [ $swapon_result -ne 0 ]; then
        echo -e "${YELLOW}swapon 单个文件失败,尝试 swapon -a${NC}"
        swapon -a 2>/dev/null
        swapon_result=$?
    fi
    
    if [ $swapon_result -eq 0 ]; then
        echo -e "${GREEN}✓ 虚拟内存已成功开启${NC}"
        log_info "swap启用成功"
        
        # 询问是否添加到fstab
        if ! grep -q "$SWAP_FILE" /etc/fstab 2>/dev/null; then
            echo ""
            read -p "是否添加到 /etc/fstab 以便开机自动启用?(y/n): " confirm
            confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
            if [ "$confirm" = "y" ]; then
                backup_fstab
                echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
                if [ $? -eq 0 ]; then
                    echo -e "${GREEN}✓ 已添加到 /etc/fstab${NC}"
                    log_info "已添加到fstab"
                else
                    echo -e "${RED}✗ 添加到fstab失败${NC}"
                    log_error "添加到fstab失败"
                fi
            fi
        else
            echo -e "${GREEN}✓ Swap文件已在fstab中配置${NC}"
        fi
    else
        echo -e "${RED}✗ 开启虚拟内存失败${NC}"
        log_error "swap启用失败"
        return 1
    fi
    
    echo ""
    show_status
    return 0
}

# -----------------------------------------------------------------------------
# 删除swap文件
# -----------------------------------------------------------------------------
swap_delete() {
    echo -e "${YELLOW}正在删除swap文件...${NC}"
    echo ""
    log_info "开始删除swap"
    
    if [ ! -f "$SWAP_FILE" ]; then
        echo -e "${RED}错误: $SWAP_FILE 不存在${NC}"
        log_error "swap文件不存在"
        return 1
    fi
    
    # 检查swap使用率
    local swap_total=$(free | awk '/Swap/ {print $2}')
    local swap_used=$(free | awk '/Swap/ {print $3}')
    
    if [ "$swap_total" -gt 0 ] 2>/dev/null && [ "$swap_used" -gt 0 ] 2>/dev/null; then
        local swap_percent=$((swap_used * 100 / swap_total))
        echo -e "${YELLOW}当前swap使用率: ${swap_percent}%${NC}"
        
        if [ "$swap_percent" -gt 80 ]; then
            echo -e "${RED}警告: swap使用率过高${NC}"
            echo -e "${CYAN}尝试清理页面缓存...${NC}"
            sync
            echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
            sleep 2
        fi
        
        echo ""
        read -p "是否继续?(y/n): " confirm
        confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
        if [ "$confirm" != "y" ]; then
            echo "操作已取消"
            log_info "用户取消删除swap"
            return 0
        fi
    fi
    
    # 关闭所有swap
    echo -e "${CYAN}正在关闭所有swap...${NC}"
    swapoff -a 2>/dev/null
    
    # 等待swap完全关闭
    if ! wait_for_swapoff "$SWAP_FILE"; then
        echo -e "${RED}✗ 无法关闭swap,文件仍在使用中${NC}"
        echo -e "${CYAN}请检查是否有进程正在使用swap${NC}"
        log_error "无法关闭swap"
        return 1
    fi
    echo -e "${GREEN}✓ Swap已关闭${NC}"
    
    # 备份并清理fstab配置
    echo -e "${CYAN}正在清理fstab配置...${NC}"
    if [ -f /etc/fstab ]; then
        backup_fstab
        
        # 只删除特定swapfile配置(修复:不过度删除)
        local original_count=$(grep -c "$SWAP_FILE" /etc/fstab 2>/dev/null || echo 0)
        sed -i "\|^$SWAP_FILE|d" /etc/fstab 2>/dev/null
        local new_count=$(grep -c "$SWAP_FILE" /etc/fstab 2>/dev/null || echo 0)
        local removed=$((original_count - new_count))
        
        if [ "$removed" -gt 0 ]; then
            echo -e "${GREEN}✓ 已删除 $removed 条swapfile配置${NC}"
            log_info "从fstab删除 $removed 条配置"
        else
            echo -e "${YELLOW}fstab中无swapfile配置${NC}"
        fi
    fi
    
    # 移除文件特殊属性
    echo -e "${CYAN}正在移除文件特殊属性...${NC}"
    chattr -i "$SWAP_FILE" 2>/dev/null
    chattr -a "$SWAP_FILE" 2>/dev/null
    log_info "已移除文件特殊属性"
    
    # 删除文件
    echo -e "${CYAN}正在删除swap文件...${NC}"
    rm -f "$SWAP_FILE"
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}✓ Swap文件已删除${NC}"
        log_info "swap文件删除成功"
    else
        echo -e "${RED}✗ 删除失败${NC}"
        echo -e "${CYAN}诊断信息:${NC}"
        ls -la "$SWAP_FILE" 2>/dev/null
        lsattr "$SWAP_FILE" 2>/dev/null
        log_error "swap文件删除失败"
        return 1
    fi
    
    # 验证删除
    if [ -f "$SWAP_FILE" ]; then
        echo -e "${RED}✗ 验证失败: 文件仍然存在${NC}"
        log_error "删除验证失败"
        return 1
    fi
    
    echo ""
    echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║          删除完成                      ║${NC}"
    echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
    echo ""
    show_status
    
    return 0
}

# -----------------------------------------------------------------------------
# 设置swappiness
# -----------------------------------------------------------------------------
set_swappiness() {
    local value="$1"
    
    # 默认值
    if [ -z "$value" ]; then
        value=60
    fi
    
    # 验证值范围
    if ! [[ "$value" =~ ^[0-9]+$ ]]; then
        echo -e "${RED}错误: swappiness值必须是数字${NC}"
        log_error "无效的swappiness值: $value"
        return 1
    fi
    
    if [ "$value" -lt 0 ] || [ "$value" -gt 100 ]; then
        echo -e "${RED}错误: swappiness值必须在 0-100 之间${NC}"
        log_error "swappiness值超出范围: $value"
        return 1
    fi
    
    log_info "设置swappiness: $value"
    
    # 临时设置
    echo "$value" > /proc/sys/vm/swappiness 2>/dev/null
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}✓ swappiness 已临时设置为 $value${NC}"
        log_info "swappiness临时设置成功"
    else
        echo -e "${RED}✗ 设置失败${NC}"
        log_error "swappiness设置失败"
        return 1
    fi
    
    # 询问是否永久保存
    echo ""
    read -p "是否永久保存此设置?(y/n): " confirm
    confirm=$(echo "$confirm" | tr '[:upper:]' '[:lower:]')
    
    if [ "$confirm" = "y" ]; then
        # 确保目录存在
        mkdir -p /etc/sysctl.d 2>/dev/null
        
        local sysctl_file="/etc/sysctl.d/99-swappiness.conf"
        echo "vm.swappiness=$value" > "$sysctl_file" 2>/dev/null
        
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}✓ 已保存到 $sysctl_file${NC}"
            log_info "swappiness永久配置保存到: $sysctl_file"
            
            # 验证配置
            sysctl -p "$sysctl_file" 2>/dev/null
            if [ $? -eq 0 ]; then
                echo -e "${GREEN}✓ 配置验证通过${NC}"
            fi
        else
            echo -e "${RED}✗ 保存配置失败${NC}"
            log_error "保存swappiness配置失败"
        fi
    fi
    
    echo ""
    echo -e "${CYAN}Swappiness值说明:${NC}"
    echo "  0   = 尽量避免使用swap (适合SSD/大内存)"
    echo "  10  = 适合桌面环境"
    echo "  60  = 默认值"
    echo "  100 = 积极使用swap (适合小内存)"
    
    return 0
}

# -----------------------------------------------------------------------------
# 显示帮助信息
# -----------------------------------------------------------------------------
show_help() {
    echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║        Swap 管理脚本 v4.0.0 (生产级)                   ║${NC}"
    echo -e "${GREEN}╚════════════════════════════════════════════════════════╝${NC}"
    echo ""
    echo -e "${CYAN}用法:${NC} sudo $SCRIPT_NAME [命令] [参数]"
    echo ""
    echo -e "${CYAN}命令:${NC}"
    echo "  on [大小]         开启虚拟内存 (可指定大小如 2G, 4G, 8G)"
    echo "  off               关闭虚拟内存"
    echo "  status            查看当前状态"
    echo "  delete            删除swap文件(自动清理配置)"
    echo "  swappiness [值]   设置swap使用倾向 (0-100)"
    echo "  restore           从备份恢复fstab配置"
    echo "  help              显示此帮助信息"
    echo ""
    echo -e "${CYAN}示例:${NC}"
    echo "  sudo $SCRIPT_NAME status              # 查看状态"
    echo "  sudo $SCRIPT_NAME on 4G               # 创建4G swap并开启"
    echo "  sudo $SCRIPT_NAME off                 # 关闭swap"
    echo "  sudo $SCRIPT_NAME delete              # 删除swap文件"
    echo "  sudo $SCRIPT_NAME swappiness 10       # 设置swappiness为10"
    echo "  sudo $SCRIPT_NAME restore             # 恢复fstab备份"
    echo ""
    echo -e "${CYAN}支持的大小单位:${NC} K, M, G (如 512M, 1G, 4G, 8G, 2GB)"
    echo ""
    echo -e "${CYAN}日志文件:${NC} $LOG_FILE"
    echo -e "${CYAN}备份目录:${NC} $FSTAB_BACKUP_DIR"
    echo ""
}

# -----------------------------------------------------------------------------
# 主程序
# -----------------------------------------------------------------------------
main() {
    init_check "$@"
    
    case "$1" in
        on)
            if [ -n "$2" ]; then
                validate_size "$2"
                swap_on "$2"
            else
                swap_on
            fi
            ;;
        off)
            swap_off
            ;;
        status)
            show_status
            ;;
        delete)
            swap_delete
            ;;
        swappiness)
            set_swappiness "$2"
            ;;
        restore)
            restore_fstab
            ;;
        help|--help|-h)
            show_help
            ;;
        "")
            echo -e "${RED}错误: 未指定命令${NC}"
            echo ""
            show_help
            exit 1
            ;;
        *)
            echo -e "${RED}错误: 未知命令 '$1'${NC}"
            echo ""
            show_help
            exit 1
            ;;
    esac
    
    log_info "========== 脚本结束 =========="
}

# 执行主程序
main "$@"